/*
 * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package java.awt;

import java.awt.dnd.DropTarget;

import java.awt.event.*;

import java.awt.peer.ContainerPeer;
import java.awt.peer.ComponentPeer;
import java.awt.peer.LightweightPeer;

import java.beans.PropertyChangeListener;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import java.io.PrintStream;
import java.io.PrintWriter;

import java.lang.ref.WeakReference;
import java.security.AccessController;

import java.util.ArrayList;
import java.util.EventListener;
import java.util.HashSet;
import java.util.Set;

import javax.accessibility.*;

import sun.util.logging.PlatformLogger;

import sun.awt.AppContext;
import sun.awt.AWTAccessor;
import sun.awt.CausedFocusEvent;
import sun.awt.PeerEvent;
import sun.awt.SunToolkit;

import sun.awt.dnd.SunDropTargetEvent;

import sun.java2d.pipe.Region;

import sun.security.action.GetBooleanAction;

/**
 * A generic Abstract Window Toolkit(AWT) container object is a component
 * that can contain other AWT components.
 * <p>
 * Components added to a container are tracked in a list.  The order
 * of the list will define the components' front-to-back stacking order
 * within the container.  If no index is specified when adding a
 * component to a container, it will be added to the end of the list
 * (and hence to the bottom of the stacking order).
 * <p>
 * <b>Note</b>: For details on the focus subsystem, see
 * <a href="https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html">
 * How to Use the Focus Subsystem</a>,
 * a section in <em>The Java Tutorial</em>, and the
 * <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
 * for more information.
 *
 * @author Arthur van Hoff
 * @author Sami Shaio
 * @see #add(java.awt.Component, int)
 * @see #getComponent(int)
 * @see LayoutManager
 * @since JDK1.0
 */
public class Container extends Component {

  private static final PlatformLogger log = PlatformLogger.getLogger("java.awt.Container");
  private static final PlatformLogger eventLog = PlatformLogger
      .getLogger("java.awt.event.Container");

  private static final Component[] EMPTY_ARRAY = new Component[0];

  /**
   * The components in this container.
   *
   * @see #add
   * @see #getComponents
   */
  private java.util.List<Component> component = new ArrayList<>();

  /**
   * Layout manager for this container.
   *
   * @see #doLayout
   * @see #setLayout
   * @see #getLayout
   */
  LayoutManager layoutMgr;

  /**
   * Event router for lightweight components.  If this container
   * is native, this dispatcher takes care of forwarding and
   * retargeting the events to lightweight components contained
   * (if any).
   */
  private LightweightDispatcher dispatcher;

  /**
   * The focus traversal policy that will manage keyboard traversal of this
   * Container's children, if this Container is a focus cycle root. If the
   * value is null, this Container inherits its policy from its focus-cycle-
   * root ancestor. If all such ancestors of this Container have null
   * policies, then the current KeyboardFocusManager's default policy is
   * used. If the value is non-null, this policy will be inherited by all
   * focus-cycle-root children that have no keyboard-traversal policy of
   * their own (as will, recursively, their focus-cycle-root children).
   * <p>
   * If this Container is not a focus cycle root, the value will be
   * remembered, but will not be used or inherited by this or any other
   * Containers until this Container is made a focus cycle root.
   *
   * @see #setFocusTraversalPolicy
   * @see #getFocusTraversalPolicy
   * @since 1.4
   */
  private transient FocusTraversalPolicy focusTraversalPolicy;

  /**
   * Indicates whether this Component is the root of a focus traversal cycle.
   * Once focus enters a traversal cycle, typically it cannot leave it via
   * focus traversal unless one of the up- or down-cycle keys is pressed.
   * Normal traversal is limited to this Container, and all of this
   * Container's descendants that are not descendants of inferior focus cycle
   * roots.
   *
   * @see #setFocusCycleRoot
   * @see #isFocusCycleRoot
   * @since 1.4
   */
  private boolean focusCycleRoot = false;


  /**
   * Stores the value of focusTraversalPolicyProvider property.
   *
   * @see #setFocusTraversalPolicyProvider
   * @since 1.5
   */
  private boolean focusTraversalPolicyProvider;

  // keeps track of the threads that are printing this component
  private transient Set<Thread> printingThreads;
  // True if there is at least one thread that's printing this component
  private transient boolean printing = false;

  transient ContainerListener containerListener;

  /* HierarchyListener and HierarchyBoundsListener support */
  transient int listeningChildren;
  transient int listeningBoundsChildren;
  transient int descendantsCount;

  /* Non-opaque window support -- see Window.setLayersOpaque */
  transient Color preserveBackgroundColor = null;

  /**
   * JDK 1.1 serialVersionUID
   */
  private static final long serialVersionUID = 4613797578919906343L;

  /**
   * A constant which toggles one of the controllable behaviors
   * of <code>getMouseEventTarget</code>. It is used to specify whether
   * the method can return the Container on which it is originally called
   * in case if none of its children are the current mouse event targets.
   *
   * @see #getMouseEventTarget(int, int, boolean)
   */
  static final boolean INCLUDE_SELF = true;

  /**
   * A constant which toggles one of the controllable behaviors
   * of <code>getMouseEventTarget</code>. It is used to specify whether
   * the method should search only lightweight components.
   *
   * @see #getMouseEventTarget(int, int, boolean)
   */
  static final boolean SEARCH_HEAVYWEIGHTS = true;

  /*
     * Number of HW or LW components in this container (including
     * all descendant containers).
     */
  private transient int numOfHWComponents = 0;
  private transient int numOfLWComponents = 0;

  private static final PlatformLogger mixingLog = PlatformLogger
      .getLogger("java.awt.mixing.Container");

  /**
   * @serialField ncomponents                     int The number of components in this container.
   * This value can be null.
   * @serialField component                       Component[] The components in this container.
   * @serialField layoutMgr                       LayoutManager Layout manager for this container.
   * @serialField dispatcher                      LightweightDispatcher Event router for lightweight
   * components.  If this container is native, this dispatcher takes care of forwarding and
   * retargeting the events to lightweight components contained (if any).
   * @serialField maxSize                         Dimension Maximum size of this Container.
   * @serialField focusCycleRoot                  boolean Indicates whether this Component is the
   * root of a focus traversal cycle. Once focus enters a traversal cycle, typically it cannot leave
   * it via focus traversal unless one of the up- or down-cycle keys is pressed. Normal traversal is
   * limited to this Container, and all of this Container's descendants that are not descendants of
   * inferior focus cycle roots.
   * @serialField containerSerializedDataVersion  int Container Serial Data Version.
   * @serialField focusTraversalPolicyProvider    boolean Stores the value of
   * focusTraversalPolicyProvider property.
   */
  private static final ObjectStreamField[] serialPersistentFields = {
      new ObjectStreamField("ncomponents", Integer.TYPE),
      new ObjectStreamField("component", Component[].class),
      new ObjectStreamField("layoutMgr", LayoutManager.class),
      new ObjectStreamField("dispatcher", LightweightDispatcher.class),
      new ObjectStreamField("maxSize", Dimension.class),
      new ObjectStreamField("focusCycleRoot", Boolean.TYPE),
      new ObjectStreamField("containerSerializedDataVersion", Integer.TYPE),
      new ObjectStreamField("focusTraversalPolicyProvider", Boolean.TYPE),
  };

  static {
        /* ensure that the necessary native libraries are loaded */
    Toolkit.loadLibraries();
    if (!GraphicsEnvironment.isHeadless()) {
      initIDs();
    }

    AWTAccessor.setContainerAccessor(new AWTAccessor.ContainerAccessor() {
      @Override
      public void validateUnconditionally(Container cont) {
        cont.validateUnconditionally();
      }

      @Override
      public Component findComponentAt(Container cont, int x, int y,
          boolean ignoreEnabled) {
        return cont.findComponentAt(x, y, ignoreEnabled);
      }
    });
  }

  /**
   * Initialize JNI field and method IDs for fields that may be
   * called from C.
   */
  private static native void initIDs();

  /**
   * Constructs a new Container. Containers can be extended directly,
   * but are lightweight in this case and must be contained by a parent
   * somewhere higher up in the component tree that is native.
   * (such as Frame for example).
   */
  public Container() {
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  void initializeFocusTraversalKeys() {
    focusTraversalKeys = new Set[4];
  }

  /**
   * Gets the number of components in this panel.
   * <p>
   * Note: This method should be called under AWT tree lock.
   *
   * @return the number of components in this panel.
   * @see #getComponent
   * @see Component#getTreeLock()
   * @since JDK1.1
   */
  public int getComponentCount() {
    return countComponents();
  }

  /**
   * @deprecated As of JDK version 1.1, replaced by getComponentCount().
   */
  @Deprecated
  public int countComponents() {
    // This method is not synchronized under AWT tree lock.
    // Instead, the calling code is responsible for the
    // synchronization. See 6784816 for details.
    return component.size();
  }

  /**
   * Gets the nth component in this container.
   * <p>
   * Note: This method should be called under AWT tree lock.
   *
   * @param n the index of the component to get.
   * @return the n<sup>th</sup> component in this container.
   * @throws ArrayIndexOutOfBoundsException if the n<sup>th</sup> value does not exist.
   * @see Component#getTreeLock()
   */
  public Component getComponent(int n) {
    // This method is not synchronized under AWT tree lock.
    // Instead, the calling code is responsible for the
    // synchronization. See 6784816 for details.
    try {
      return component.get(n);
    } catch (IndexOutOfBoundsException z) {
      throw new ArrayIndexOutOfBoundsException("No such child: " + n);
    }
  }

  /**
   * Gets all the components in this container.
   * <p>
   * Note: This method should be called under AWT tree lock.
   *
   * @return an array of all the components in this container.
   * @see Component#getTreeLock()
   */
  public Component[] getComponents() {
    // This method is not synchronized under AWT tree lock.
    // Instead, the calling code is responsible for the
    // synchronization. See 6784816 for details.
    return getComponents_NoClientCode();
  }

  // NOTE: This method may be called by privileged threads.
  //       This functionality is implemented in a package-private method
  //       to insure that it cannot be overridden by client subclasses.
  //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
  final Component[] getComponents_NoClientCode() {
    return component.toArray(EMPTY_ARRAY);
  }

  /*
     * Wrapper for getComponents() method with a proper synchronization.
     */
  Component[] getComponentsSync() {
    synchronized (getTreeLock()) {
      return getComponents();
    }
  }

  /**
   * Determines the insets of this container, which indicate the size
   * of the container's border.
   * <p>
   * A <code>Frame</code> object, for example, has a top inset that
   * corresponds to the height of the frame's title bar.
   *
   * @return the insets of this container.
   * @see Insets
   * @see LayoutManager
   * @since JDK1.1
   */
  public Insets getInsets() {
    return insets();
  }

  /**
   * @deprecated As of JDK version 1.1, replaced by <code>getInsets()</code>.
   */
  @Deprecated
  public Insets insets() {
    ComponentPeer peer = this.peer;
    if (peer instanceof ContainerPeer) {
      ContainerPeer cpeer = (ContainerPeer) peer;
      return (Insets) cpeer.getInsets().clone();
    }
    return new Insets(0, 0, 0, 0);
  }

  /**
   * Appends the specified component to the end of this container.
   * This is a convenience method for {@link #addImpl}.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy. If the container has already been
   * displayed, the hierarchy must be validated thereafter in order to
   * display the added component.
   *
   * @param comp the component to be added
   * @return the component argument
   * @throws NullPointerException if {@code comp} is {@code null}
   * @see #addImpl
   * @see #invalidate
   * @see #validate
   * @see javax.swing.JComponent#revalidate()
   */
  public Component add(Component comp) {
    addImpl(comp, null, -1);
    return comp;
  }

  /**
   * Adds the specified component to this container.
   * This is a convenience method for {@link #addImpl}.
   * <p>
   * This method is obsolete as of 1.1.  Please use the
   * method <code>add(Component, Object)</code> instead.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy. If the container has already been
   * displayed, the hierarchy must be validated thereafter in order to
   * display the added component.
   *
   * @throws NullPointerException if {@code comp} is {@code null}
   * @see #add(Component, Object)
   * @see #invalidate
   */
  public Component add(String name, Component comp) {
    addImpl(comp, name, -1);
    return comp;
  }

  /**
   * Adds the specified component to this container at the given
   * position.
   * This is a convenience method for {@link #addImpl}.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy. If the container has already been
   * displayed, the hierarchy must be validated thereafter in order to
   * display the added component.
   *
   * @param comp the component to be added
   * @param index the position at which to insert the component, or <code>-1</code> to append the
   * component to the end
   * @return the component <code>comp</code>
   * @throws NullPointerException if {@code comp} is {@code null}
   * @throws IllegalArgumentException if {@code index} is invalid (see {@link #addImpl} for
   * details)
   * @see #addImpl
   * @see #remove
   * @see #invalidate
   * @see #validate
   * @see javax.swing.JComponent#revalidate()
   */
  public Component add(Component comp, int index) {
    addImpl(comp, null, index);
    return comp;
  }

  /**
   * Checks that the component
   * isn't supposed to be added into itself.
   */
  private void checkAddToSelf(Component comp) {
    if (comp instanceof Container) {
      for (Container cn = this; cn != null; cn = cn.parent) {
        if (cn == comp) {
          throw new IllegalArgumentException("adding container's parent to itself");
        }
      }
    }
  }

  /**
   * Checks that the component is not a Window instance.
   */
  private void checkNotAWindow(Component comp) {
    if (comp instanceof Window) {
      throw new IllegalArgumentException("adding a window to a container");
    }
  }

  /**
   * Checks that the component comp can be added to this container
   * Checks :  index in bounds of container's size,
   * comp is not one of this container's parents,
   * and comp is not a window.
   * Comp and container must be on the same GraphicsDevice.
   * if comp is container, all sub-components must be on
   * same GraphicsDevice.
   *
   * @since 1.5
   */
  private void checkAdding(Component comp, int index) {
    checkTreeLock();

    GraphicsConfiguration thisGC = getGraphicsConfiguration();

    if (index > component.size() || index < 0) {
      throw new IllegalArgumentException("illegal component position");
    }
    if (comp.parent == this) {
      if (index == component.size()) {
        throw new IllegalArgumentException("illegal component position " +
            index + " should be less then " + component.size());
      }
    }
    checkAddToSelf(comp);
    checkNotAWindow(comp);

    Window thisTopLevel = getContainingWindow();
    Window compTopLevel = comp.getContainingWindow();
    if (thisTopLevel != compTopLevel) {
      throw new IllegalArgumentException(
          "component and container should be in the same top-level window");
    }
    if (thisGC != null) {
      comp.checkGD(thisGC.getDevice().getIDstring());
    }
  }

  /**
   * Removes component comp from this container without making unneccessary changes
   * and generating unneccessary events. This function intended to perform optimized
   * remove, for example, if newParent and current parent are the same it just changes
   * index without calling removeNotify.
   * Note: Should be called while holding treeLock
   * Returns whether removeNotify was invoked
   *
   * @since: 1.5
   */
  private boolean removeDelicately(Component comp, Container newParent, int newIndex) {
    checkTreeLock();

    int index = getComponentZOrder(comp);
    boolean needRemoveNotify = isRemoveNotifyNeeded(comp, this, newParent);
    if (needRemoveNotify) {
      comp.removeNotify();
    }
    if (newParent != this) {
      if (layoutMgr != null) {
        layoutMgr.removeLayoutComponent(comp);
      }
      adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
          -comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
      adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
          -comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
      adjustDescendants(-(comp.countHierarchyMembers()));

      comp.parent = null;
      if (needRemoveNotify) {
        comp.setGraphicsConfiguration(null);
      }
      component.remove(index);

      invalidateIfValid();
    } else {
      // We should remove component and then
      // add it by the newIndex without newIndex decrement if even we shift components to the left
      // after remove. Consult the rules below:
      // 2->4: 012345 -> 013425, 2->5: 012345 -> 013452
      // 4->2: 012345 -> 014235
      component.remove(index);
      component.add(newIndex, comp);
    }
    if (comp.parent == null) { // was actually removed
      if (containerListener != null ||
          (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
          Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
        ContainerEvent e = new ContainerEvent(this,
            ContainerEvent.COMPONENT_REMOVED,
            comp);
        dispatchEvent(e);

      }
      comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
          this, HierarchyEvent.PARENT_CHANGED,
          Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
      if (peer != null && layoutMgr == null && isVisible()) {
        updateCursorImmediately();
      }
    }
    return needRemoveNotify;
  }

  /**
   * Checks whether this container can contain component which is focus owner.
   * Verifies that container is enable and showing, and if it is focus cycle root
   * its FTP allows component to be focus owner
   *
   * @since 1.5
   */
  boolean canContainFocusOwner(Component focusOwnerCandidate) {
    if (!(isEnabled() && isDisplayable()
        && isVisible() && isFocusable())) {
      return false;
    }
    if (isFocusCycleRoot()) {
      FocusTraversalPolicy policy = getFocusTraversalPolicy();
      if (policy instanceof DefaultFocusTraversalPolicy) {
        if (!((DefaultFocusTraversalPolicy) policy).accept(focusOwnerCandidate)) {
          return false;
        }
      }
    }
    synchronized (getTreeLock()) {
      if (parent != null) {
        return parent.canContainFocusOwner(focusOwnerCandidate);
      }
    }
    return true;
  }

  /**
   * Checks whether or not this container has heavyweight children.
   * Note: Should be called while holding tree lock
   *
   * @return true if there is at least one heavyweight children in a container, false otherwise
   * @since 1.5
   */
  final boolean hasHeavyweightDescendants() {
    checkTreeLock();
    return numOfHWComponents > 0;
  }

  /**
   * Checks whether or not this container has lightweight children.
   * Note: Should be called while holding tree lock
   *
   * @return true if there is at least one lightweight children in a container, false otherwise
   * @since 1.7
   */
  final boolean hasLightweightDescendants() {
    checkTreeLock();
    return numOfLWComponents > 0;
  }

  /**
   * Returns closest heavyweight component to this container. If this container is heavyweight
   * returns this.
   *
   * @since 1.5
   */
  Container getHeavyweightContainer() {
    checkTreeLock();
    if (peer != null && !(peer instanceof LightweightPeer)) {
      return this;
    } else {
      return getNativeContainer();
    }
  }

  /**
   * Detects whether or not remove from current parent and adding to new parent requires call of
   * removeNotify on the component. Since removeNotify destroys native window this might (not)
   * be required. For example, if new container and old containers are the same we don't need to
   * destroy native window.
   *
   * @since: 1.5
   */
  private static boolean isRemoveNotifyNeeded(Component comp, Container oldContainer,
      Container newContainer) {
    if (oldContainer == null) { // Component didn't have parent - no removeNotify
      return false;
    }
    if (comp.peer == null) { // Component didn't have peer - no removeNotify
      return false;
    }
    if (newContainer.peer == null) {
      // Component has peer but new Container doesn't - call removeNotify
      return true;
    }

    // If component is lightweight non-Container or lightweight Container with all but heavyweight
    // children there is no need to call remove notify
    if (comp.isLightweight()) {
      boolean isContainer = comp instanceof Container;

      if (!isContainer || (isContainer && !((Container) comp).hasHeavyweightDescendants())) {
        return false;
      }
    }

    // If this point is reached, then the comp is either a HW or a LW container with HW descendants.

    // All three components have peers, check for peer change
    Container newNativeContainer = oldContainer.getHeavyweightContainer();
    Container oldNativeContainer = newContainer.getHeavyweightContainer();
    if (newNativeContainer != oldNativeContainer) {
      // Native containers change - check whether or not current platform supports
      // changing of widget hierarchy on native level without recreation.
      // The current implementation forbids reparenting of LW containers with HW descendants
      // into another native container w/o destroying the peers. Actually such an operation
      // is quite rare. If we ever need to save the peers, we'll have to slightly change the
      // addDelicately() method in order to handle such LW containers recursively, reparenting
      // each HW descendant independently.
      return !comp.peer.isReparentSupported();
    } else {
      return false;
    }
  }

  /**
   * Moves the specified component to the specified z-order index in
   * the container. The z-order determines the order that components
   * are painted; the component with the highest z-order paints first
   * and the component with the lowest z-order paints last.
   * Where components overlap, the component with the lower
   * z-order paints over the component with the higher z-order.
   * <p>
   * If the component is a child of some other container, it is
   * removed from that container before being added to this container.
   * The important difference between this method and
   * <code>java.awt.Container.add(Component, int)</code> is that this method
   * doesn't call <code>removeNotify</code> on the component while
   * removing it from its previous container unless necessary and when
   * allowed by the underlying native windowing system. This way, if the
   * component has the keyboard focus, it maintains the focus when
   * moved to the new position.
   * <p>
   * This property is guaranteed to apply only to lightweight
   * non-<code>Container</code> components.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy.
   * <p>
   * <b>Note</b>: Not all platforms support changing the z-order of
   * heavyweight components from one container into another without
   * the call to <code>removeNotify</code>. There is no way to detect
   * whether a platform supports this, so developers shouldn't make
   * any assumptions.
   *
   * @param comp the component to be moved
   * @param index the position in the container's list to insert the component, where
   * <code>getComponentCount()</code> appends to the end
   * @throws NullPointerException if <code>comp</code> is <code>null</code>
   * @throws IllegalArgumentException if <code>comp</code> is one of the container's parents
   * @throws IllegalArgumentException if <code>index</code> is not in the range <code>[0,
   * getComponentCount()]</code> for moving between containers, or not in the range <code>[0,
   * getComponentCount()-1]</code> for moving inside a container
   * @throws IllegalArgumentException if adding a container to itself
   * @throws IllegalArgumentException if adding a <code>Window</code> to a container
   * @see #getComponentZOrder(java.awt.Component)
   * @see #invalidate
   * @since 1.5
   */
  public void setComponentZOrder(Component comp, int index) {
    synchronized (getTreeLock()) {
      // Store parent because remove will clear it
      Container curParent = comp.parent;
      int oldZindex = getComponentZOrder(comp);

      if (curParent == this && index == oldZindex) {
        return;
      }
      checkAdding(comp, index);

      boolean peerRecreated = (curParent != null) ?
          curParent.removeDelicately(comp, this, index) : false;

      addDelicately(comp, curParent, index);

      // If the oldZindex == -1, the component gets inserted,
      // rather than it changes its z-order.
      if (!peerRecreated && oldZindex != -1) {
        // The new 'index' cannot be == -1.
        // It gets checked at the checkAdding() method.
        // Therefore both oldZIndex and index denote
        // some existing positions at this point and
        // this is actually a Z-order changing.
        comp.mixOnZOrderChanging(oldZindex, index);
      }
    }
  }

  /**
   * Traverses the tree of components and reparents children heavyweight component
   * to new heavyweight parent.
   *
   * @since 1.5
   */
  private void reparentTraverse(ContainerPeer parentPeer, Container child) {
    checkTreeLock();

    for (int i = 0; i < child.getComponentCount(); i++) {
      Component comp = child.getComponent(i);
      if (comp.isLightweight()) {
        // If components is lightweight check if it is container
        // If it is container it might contain heavyweight children we need to reparent
        if (comp instanceof Container) {
          reparentTraverse(parentPeer, (Container) comp);
        }
      } else {
        // Q: Need to update NativeInLightFixer?
        comp.getPeer().reparent(parentPeer);
      }
    }
  }

  /**
   * Reparents child component peer to this container peer.
   * Container must be heavyweight.
   *
   * @since 1.5
   */
  private void reparentChild(Component comp) {
    checkTreeLock();
    if (comp == null) {
      return;
    }
    if (comp.isLightweight()) {
      // If component is lightweight container we need to reparent all its explicit  heavyweight children
      if (comp instanceof Container) {
        // Traverse component's tree till depth-first until encountering heavyweight component
        reparentTraverse((ContainerPeer) getPeer(), (Container) comp);
      }
    } else {
      comp.getPeer().reparent((ContainerPeer) getPeer());
    }
  }

  /**
   * Adds component to this container. Tries to minimize side effects of this adding -
   * doesn't call remove notify if it is not required.
   *
   * @since 1.5
   */
  private void addDelicately(Component comp, Container curParent, int index) {
    checkTreeLock();

    // Check if moving between containers
    if (curParent != this) {
      //index == -1 means add to the end.
      if (index == -1) {
        component.add(comp);
      } else {
        component.add(index, comp);
      }
      comp.parent = this;
      comp.setGraphicsConfiguration(getGraphicsConfiguration());

      adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
          comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
      adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
          comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
      adjustDescendants(comp.countHierarchyMembers());
    } else {
      if (index < component.size()) {
        component.set(index, comp);
      }
    }

    invalidateIfValid();
    if (peer != null) {
      if (comp.peer == null) { // Remove notify was called or it didn't have peer - create new one
        comp.addNotify();
      } else { // Both container and child have peers, it means child peer should be reparented.
        // In both cases we need to reparent native widgets.
        Container newNativeContainer = getHeavyweightContainer();
        Container oldNativeContainer = curParent.getHeavyweightContainer();
        if (oldNativeContainer != newNativeContainer) {
          // Native container changed - need to reparent native widgets
          newNativeContainer.reparentChild(comp);
        }
        comp.updateZOrder();

        if (!comp.isLightweight() && isLightweight()) {
          // If component is heavyweight and one of the containers is lightweight
          // the location of the component should be fixed.
          comp.relocateComponent();
        }
      }
    }
    if (curParent != this) {
            /* Notify the layout manager of the added component. */
      if (layoutMgr != null) {
        if (layoutMgr instanceof LayoutManager2) {
          ((LayoutManager2) layoutMgr).addLayoutComponent(comp, null);
        } else {
          layoutMgr.addLayoutComponent(null, comp);
        }
      }
      if (containerListener != null ||
          (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
          Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
        ContainerEvent e = new ContainerEvent(this,
            ContainerEvent.COMPONENT_ADDED,
            comp);
        dispatchEvent(e);
      }
      comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
          this, HierarchyEvent.PARENT_CHANGED,
          Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));

      // If component is focus owner or parent container of focus owner check that after reparenting
      // focus owner moved out if new container prohibit this kind of focus owner.
      if (comp.isFocusOwner() && !comp.canBeFocusOwnerRecursively()) {
        comp.transferFocus();
      } else if (comp instanceof Container) {
        Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager()
            .getFocusOwner();
        if (focusOwner != null && isParentOf(focusOwner) && !focusOwner
            .canBeFocusOwnerRecursively()) {
          focusOwner.transferFocus();
        }
      }
    } else {
      comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
          this, HierarchyEvent.HIERARCHY_CHANGED,
          Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
    }

    if (peer != null && layoutMgr == null && isVisible()) {
      updateCursorImmediately();
    }
  }

  /**
   * Returns the z-order index of the component inside the container.
   * The higher a component is in the z-order hierarchy, the lower
   * its index.  The component with the lowest z-order index is
   * painted last, above all other child components.
   *
   * @param comp the component being queried
   * @return the z-order index of the component; otherwise returns -1 if the component is
   * <code>null</code> or doesn't belong to the container
   * @see #setComponentZOrder(java.awt.Component, int)
   * @since 1.5
   */
  public int getComponentZOrder(Component comp) {
    if (comp == null) {
      return -1;
    }
    synchronized (getTreeLock()) {
      // Quick check - container should be immediate parent of the component
      if (comp.parent != this) {
        return -1;
      }
      return component.indexOf(comp);
    }
  }

  /**
   * Adds the specified component to the end of this container.
   * Also notifies the layout manager to add the component to
   * this container's layout using the specified constraints object.
   * This is a convenience method for {@link #addImpl}.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy. If the container has already been
   * displayed, the hierarchy must be validated thereafter in order to
   * display the added component.
   *
   * @param comp the component to be added
   * @param constraints an object expressing layout constraints for this component
   * @throws NullPointerException if {@code comp} is {@code null}
   * @see #addImpl
   * @see #invalidate
   * @see #validate
   * @see javax.swing.JComponent#revalidate()
   * @see LayoutManager
   * @since JDK1.1
   */
  public void add(Component comp, Object constraints) {
    addImpl(comp, constraints, -1);
  }

  /**
   * Adds the specified component to this container with the specified
   * constraints at the specified index.  Also notifies the layout
   * manager to add the component to the this container's layout using
   * the specified constraints object.
   * This is a convenience method for {@link #addImpl}.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy. If the container has already been
   * displayed, the hierarchy must be validated thereafter in order to
   * display the added component.
   *
   * @param comp the component to be added
   * @param constraints an object expressing layout constraints for this
   * @param index the position in the container's list at which to insert the component;
   * <code>-1</code> means insert at the end component
   * @throws NullPointerException if {@code comp} is {@code null}
   * @throws IllegalArgumentException if {@code index} is invalid (see {@link #addImpl} for
   * details)
   * @see #addImpl
   * @see #invalidate
   * @see #validate
   * @see javax.swing.JComponent#revalidate()
   * @see #remove
   * @see LayoutManager
   */
  public void add(Component comp, Object constraints, int index) {
    addImpl(comp, constraints, index);
  }

  /**
   * Adds the specified component to this container at the specified
   * index. This method also notifies the layout manager to add
   * the component to this container's layout using the specified
   * constraints object via the <code>addLayoutComponent</code>
   * method.
   * <p>
   * The constraints are
   * defined by the particular layout manager being used.  For
   * example, the <code>BorderLayout</code> class defines five
   * constraints: <code>BorderLayout.NORTH</code>,
   * <code>BorderLayout.SOUTH</code>, <code>BorderLayout.EAST</code>,
   * <code>BorderLayout.WEST</code>, and <code>BorderLayout.CENTER</code>.
   * <p>
   * The <code>GridBagLayout</code> class requires a
   * <code>GridBagConstraints</code> object.  Failure to pass
   * the correct type of constraints object results in an
   * <code>IllegalArgumentException</code>.
   * <p>
   * If the current layout manager implements {@code LayoutManager2}, then
   * {@link LayoutManager2#addLayoutComponent(Component, Object)} is invoked on
   * it. If the current layout manager does not implement
   * {@code LayoutManager2}, and constraints is a {@code String}, then
   * {@link LayoutManager#addLayoutComponent(String, Component)} is invoked on it.
   * <p>
   * If the component is not an ancestor of this container and has a non-null
   * parent, it is removed from its current parent before it is added to this
   * container.
   * <p>
   * This is the method to override if a program needs to track
   * every add request to a container as all other add methods defer
   * to this one. An overriding method should
   * usually include a call to the superclass's version of the method:
   *
   * <blockquote>
   * <code>super.addImpl(comp, constraints, index)</code>
   * </blockquote>
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy. If the container has already been
   * displayed, the hierarchy must be validated thereafter in order to
   * display the added component.
   *
   * @param comp the component to be added
   * @param constraints an object expressing layout constraints for this component
   * @param index the position in the container's list at which to insert the component, where
   * <code>-1</code> means append to the end
   * @throws IllegalArgumentException if {@code index} is invalid; if {@code comp} is a child of
   * this container, the valid range is {@code [-1, getComponentCount()-1]}; if component is not a
   * child of this container, the valid range is {@code [-1, getComponentCount()]}
   * @throws IllegalArgumentException if {@code comp} is an ancestor of this container
   * @throws IllegalArgumentException if adding a window to a container
   * @throws NullPointerException if {@code comp} is {@code null}
   * @see #add(Component)
   * @see #add(Component, int)
   * @see #add(Component, java.lang.Object)
   * @see #invalidate
   * @see LayoutManager
   * @see LayoutManager2
   * @since JDK1.1
   */
  protected void addImpl(Component comp, Object constraints, int index) {
    synchronized (getTreeLock()) {
            /* Check for correct arguments:  index in bounds,
             * comp cannot be one of this container's parents,
             * and comp cannot be a window.
             * comp and container must be on the same GraphicsDevice.
             * if comp is container, all sub-components must be on
             * same GraphicsDevice.
             */
      GraphicsConfiguration thisGC = this.getGraphicsConfiguration();

      if (index > component.size() || (index < 0 && index != -1)) {
        throw new IllegalArgumentException(
            "illegal component position");
      }
      checkAddToSelf(comp);
      checkNotAWindow(comp);
      if (thisGC != null) {
        comp.checkGD(thisGC.getDevice().getIDstring());
      }

            /* Reparent the component and tidy up the tree's state. */
      if (comp.parent != null) {
        comp.parent.remove(comp);
        if (index > component.size()) {
          throw new IllegalArgumentException("illegal component position");
        }
      }

      //index == -1 means add to the end.
      if (index == -1) {
        component.add(comp);
      } else {
        component.add(index, comp);
      }
      comp.parent = this;
      comp.setGraphicsConfiguration(thisGC);

      adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
          comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
      adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
          comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
      adjustDescendants(comp.countHierarchyMembers());

      invalidateIfValid();
      if (peer != null) {
        comp.addNotify();
      }

            /* Notify the layout manager of the added component. */
      if (layoutMgr != null) {
        if (layoutMgr instanceof LayoutManager2) {
          ((LayoutManager2) layoutMgr).addLayoutComponent(comp, constraints);
        } else if (constraints instanceof String) {
          layoutMgr.addLayoutComponent((String) constraints, comp);
        }
      }
      if (containerListener != null ||
          (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
          Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
        ContainerEvent e = new ContainerEvent(this,
            ContainerEvent.COMPONENT_ADDED,
            comp);
        dispatchEvent(e);
      }

      comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
          this, HierarchyEvent.PARENT_CHANGED,
          Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
      if (peer != null && layoutMgr == null && isVisible()) {
        updateCursorImmediately();
      }
    }
  }

  @Override
  boolean updateGraphicsData(GraphicsConfiguration gc) {
    checkTreeLock();

    boolean ret = super.updateGraphicsData(gc);

    for (Component comp : component) {
      if (comp != null) {
        ret |= comp.updateGraphicsData(gc);
      }
    }
    return ret;
  }

  /**
   * Checks that all Components that this Container contains are on
   * the same GraphicsDevice as this Container.  If not, throws an
   * IllegalArgumentException.
   */
  void checkGD(String stringID) {
    for (Component comp : component) {
      if (comp != null) {
        comp.checkGD(stringID);
      }
    }
  }

  /**
   * Removes the component, specified by <code>index</code>,
   * from this container.
   * This method also notifies the layout manager to remove the
   * component from this container's layout via the
   * <code>removeLayoutComponent</code> method.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy. If the container has already been
   * displayed, the hierarchy must be validated thereafter in order to
   * reflect the changes.
   *
   * @param index the index of the component to be removed
   * @throws ArrayIndexOutOfBoundsException if {@code index} is not in range {@code [0,
   * getComponentCount()-1]}
   * @see #add
   * @see #invalidate
   * @see #validate
   * @see #getComponentCount
   * @since JDK1.1
   */
  public void remove(int index) {
    synchronized (getTreeLock()) {
      if (index < 0 || index >= component.size()) {
        throw new ArrayIndexOutOfBoundsException(index);
      }
      Component comp = component.get(index);
      if (peer != null) {
        comp.removeNotify();
      }
      if (layoutMgr != null) {
        layoutMgr.removeLayoutComponent(comp);
      }

      adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
          -comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
      adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
          -comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
      adjustDescendants(-(comp.countHierarchyMembers()));

      comp.parent = null;
      component.remove(index);
      comp.setGraphicsConfiguration(null);

      invalidateIfValid();
      if (containerListener != null ||
          (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
          Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
        ContainerEvent e = new ContainerEvent(this,
            ContainerEvent.COMPONENT_REMOVED,
            comp);
        dispatchEvent(e);
      }

      comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
          this, HierarchyEvent.PARENT_CHANGED,
          Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
      if (peer != null && layoutMgr == null && isVisible()) {
        updateCursorImmediately();
      }
    }
  }

  /**
   * Removes the specified component from this container.
   * This method also notifies the layout manager to remove the
   * component from this container's layout via the
   * <code>removeLayoutComponent</code> method.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy. If the container has already been
   * displayed, the hierarchy must be validated thereafter in order to
   * reflect the changes.
   *
   * @param comp the component to be removed
   * @throws NullPointerException if {@code comp} is {@code null}
   * @see #add
   * @see #invalidate
   * @see #validate
   * @see #remove(int)
   */
  public void remove(Component comp) {
    synchronized (getTreeLock()) {
      if (comp.parent == this) {
        int index = component.indexOf(comp);
        if (index >= 0) {
          remove(index);
        }
      }
    }
  }

  /**
   * Removes all the components from this container.
   * This method also notifies the layout manager to remove the
   * components from this container's layout via the
   * <code>removeLayoutComponent</code> method.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy. If the container has already been
   * displayed, the hierarchy must be validated thereafter in order to
   * reflect the changes.
   *
   * @see #add
   * @see #remove
   * @see #invalidate
   */
  public void removeAll() {
    synchronized (getTreeLock()) {
      adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
          -listeningChildren);
      adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
          -listeningBoundsChildren);
      adjustDescendants(-descendantsCount);

      while (!component.isEmpty()) {
        Component comp = component.remove(component.size() - 1);

        if (peer != null) {
          comp.removeNotify();
        }
        if (layoutMgr != null) {
          layoutMgr.removeLayoutComponent(comp);
        }
        comp.parent = null;
        comp.setGraphicsConfiguration(null);
        if (containerListener != null ||
            (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
            Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
          ContainerEvent e = new ContainerEvent(this,
              ContainerEvent.COMPONENT_REMOVED,
              comp);
          dispatchEvent(e);
        }

        comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED,
            comp, this,
            HierarchyEvent.PARENT_CHANGED,
            Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
      }
      if (peer != null && layoutMgr == null && isVisible()) {
        updateCursorImmediately();
      }
      invalidateIfValid();
    }
  }

  // Should only be called while holding tree lock
  int numListening(long mask) {
    int superListening = super.numListening(mask);

    if (mask == AWTEvent.HIERARCHY_EVENT_MASK) {
      if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {
        // Verify listeningChildren is correct
        int sum = 0;
        for (Component comp : component) {
          sum += comp.numListening(mask);
        }
        if (listeningChildren != sum) {
          eventLog.fine("Assertion (listeningChildren == sum) failed");
        }
      }
      return listeningChildren + superListening;
    } else if (mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) {
      if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {
        // Verify listeningBoundsChildren is correct
        int sum = 0;
        for (Component comp : component) {
          sum += comp.numListening(mask);
        }
        if (listeningBoundsChildren != sum) {
          eventLog.fine("Assertion (listeningBoundsChildren == sum) failed");
        }
      }
      return listeningBoundsChildren + superListening;
    } else {
      // assert false;
      if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {
        eventLog.fine("This code must never be reached");
      }
      return superListening;
    }
  }

  // Should only be called while holding tree lock
  void adjustListeningChildren(long mask, int num) {
    if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {
      boolean toAssert = (mask == AWTEvent.HIERARCHY_EVENT_MASK ||
          mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK ||
          mask == (AWTEvent.HIERARCHY_EVENT_MASK |
              AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
      if (!toAssert) {
        eventLog.fine("Assertion failed");
      }
    }

    if (num == 0) {
      return;
    }

    if ((mask & AWTEvent.HIERARCHY_EVENT_MASK) != 0) {
      listeningChildren += num;
    }
    if ((mask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0) {
      listeningBoundsChildren += num;
    }

    adjustListeningChildrenOnParent(mask, num);
  }

  // Should only be called while holding tree lock
  void adjustDescendants(int num) {
    if (num == 0) {
      return;
    }

    descendantsCount += num;
    adjustDecendantsOnParent(num);
  }

  // Should only be called while holding tree lock
  void adjustDecendantsOnParent(int num) {
    if (parent != null) {
      parent.adjustDescendants(num);
    }
  }

  // Should only be called while holding tree lock
  int countHierarchyMembers() {
    if (log.isLoggable(PlatformLogger.Level.FINE)) {
      // Verify descendantsCount is correct
      int sum = 0;
      for (Component comp : component) {
        sum += comp.countHierarchyMembers();
      }
      if (descendantsCount != sum) {
        log.fine("Assertion (descendantsCount == sum) failed");
      }
    }
    return descendantsCount + 1;
  }

  private int getListenersCount(int id, boolean enabledOnToolkit) {
    checkTreeLock();
    if (enabledOnToolkit) {
      return descendantsCount;
    }
    switch (id) {
      case HierarchyEvent.HIERARCHY_CHANGED:
        return listeningChildren;
      case HierarchyEvent.ANCESTOR_MOVED:
      case HierarchyEvent.ANCESTOR_RESIZED:
        return listeningBoundsChildren;
      default:
        return 0;
    }
  }

  final int createHierarchyEvents(int id, Component changed,
      Container changedParent, long changeFlags, boolean enabledOnToolkit) {
    checkTreeLock();
    int listeners = getListenersCount(id, enabledOnToolkit);

    for (int count = listeners, i = 0; count > 0; i++) {
      count -= component.get(i).createHierarchyEvents(id, changed,
          changedParent, changeFlags, enabledOnToolkit);
    }
    return listeners +
        super.createHierarchyEvents(id, changed, changedParent,
            changeFlags, enabledOnToolkit);
  }

  final void createChildHierarchyEvents(int id, long changeFlags,
      boolean enabledOnToolkit) {
    checkTreeLock();
    if (component.isEmpty()) {
      return;
    }
    int listeners = getListenersCount(id, enabledOnToolkit);

    for (int count = listeners, i = 0; count > 0; i++) {
      count -= component.get(i).createHierarchyEvents(id, this, parent,
          changeFlags, enabledOnToolkit);
    }
  }

  /**
   * Gets the layout manager for this container.
   *
   * @see #doLayout
   * @see #setLayout
   */
  public LayoutManager getLayout() {
    return layoutMgr;
  }

  /**
   * Sets the layout manager for this container.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy.
   *
   * @param mgr the specified layout manager
   * @see #doLayout
   * @see #getLayout
   * @see #invalidate
   */
  public void setLayout(LayoutManager mgr) {
    layoutMgr = mgr;
    invalidateIfValid();
  }

  /**
   * Causes this container to lay out its components.  Most programs
   * should not call this method directly, but should invoke
   * the <code>validate</code> method instead.
   *
   * @see LayoutManager#layoutContainer
   * @see #setLayout
   * @see #validate
   * @since JDK1.1
   */
  public void doLayout() {
    layout();
  }

  /**
   * @deprecated As of JDK version 1.1, replaced by <code>doLayout()</code>.
   */
  @Deprecated
  public void layout() {
    LayoutManager layoutMgr = this.layoutMgr;
    if (layoutMgr != null) {
      layoutMgr.layoutContainer(this);
    }
  }

  /**
   * Indicates if this container is a <i>validate root</i>.
   * <p>
   * Layout-related changes, such as bounds of the validate root descendants,
   * do not affect the layout of the validate root parent. This peculiarity
   * enables the {@code invalidate()} method to stop invalidating the
   * component hierarchy when the method encounters a validate root. However,
   * to preserve backward compatibility this new optimized behavior is
   * enabled only when the {@code java.awt.smartInvalidate} system property
   * value is set to {@code true}.
   * <p>
   * If a component hierarchy contains validate roots and the new optimized
   * {@code invalidate()} behavior is enabled, the {@code validate()} method
   * must be invoked on the validate root of a previously invalidated
   * component to restore the validity of the hierarchy later. Otherwise,
   * calling the {@code validate()} method on the top-level container (such
   * as a {@code Frame} object) should be used to restore the validity of the
   * component hierarchy.
   * <p>
   * The {@code Window} class and the {@code Applet} class are the validate
   * roots in AWT.  Swing introduces more validate roots.
   *
   * @return whether this container is a validate root
   * @see #invalidate
   * @see java.awt.Component#invalidate
   * @see javax.swing.JComponent#isValidateRoot
   * @see javax.swing.JComponent#revalidate
   * @since 1.7
   */
  public boolean isValidateRoot() {
    return false;
  }

  private static final boolean isJavaAwtSmartInvalidate;

  static {
    // Don't lazy-read because every app uses invalidate()
    isJavaAwtSmartInvalidate = AccessController.doPrivileged(
        new GetBooleanAction("java.awt.smartInvalidate"));
  }

  /**
   * Invalidates the parent of the container unless the container
   * is a validate root.
   */
  @Override
  void invalidateParent() {
    if (!isJavaAwtSmartInvalidate || !isValidateRoot()) {
      super.invalidateParent();
    }
  }

  /**
   * Invalidates the container.
   * <p>
   * If the {@code LayoutManager} installed on this container is an instance
   * of the {@code LayoutManager2} interface, then
   * the {@link LayoutManager2#invalidateLayout(Container)} method is invoked
   * on it supplying this {@code Container} as the argument.
   * <p>
   * Afterwards this method marks this container invalid, and invalidates its
   * ancestors. See the {@link Component#invalidate} method for more details.
   *
   * @see #validate
   * @see #layout
   * @see LayoutManager2
   */
  @Override
  public void invalidate() {
    LayoutManager layoutMgr = this.layoutMgr;
    if (layoutMgr instanceof LayoutManager2) {
      LayoutManager2 lm = (LayoutManager2) layoutMgr;
      lm.invalidateLayout(this);
    }
    super.invalidate();
  }

  /**
   * Validates this container and all of its subcomponents.
   * <p>
   * Validating a container means laying out its subcomponents.
   * Layout-related changes, such as setting the bounds of a component, or
   * adding a component to the container, invalidate the container
   * automatically.  Note that the ancestors of the container may be
   * invalidated also (see {@link Component#invalidate} for details.)
   * Therefore, to restore the validity of the hierarchy, the {@code
   * validate()} method should be invoked on the top-most invalid
   * container of the hierarchy.
   * <p>
   * Validating the container may be a quite time-consuming operation. For
   * performance reasons a developer may postpone the validation of the
   * hierarchy till a set of layout-related operations completes, e.g. after
   * adding all the children to the container.
   * <p>
   * If this {@code Container} is not valid, this method invokes
   * the {@code validateTree} method and marks this {@code Container}
   * as valid. Otherwise, no action is performed.
   *
   * @see #add(java.awt.Component)
   * @see #invalidate
   * @see Container#isValidateRoot
   * @see javax.swing.JComponent#revalidate()
   * @see #validateTree
   */
  public void validate() {
    boolean updateCur = false;
    synchronized (getTreeLock()) {
      if ((!isValid() || descendUnconditionallyWhenValidating)
          && peer != null) {
        ContainerPeer p = null;
        if (peer instanceof ContainerPeer) {
          p = (ContainerPeer) peer;
        }
        if (p != null) {
          p.beginValidate();
        }
        validateTree();
        if (p != null) {
          p.endValidate();
          // Avoid updating cursor if this is an internal call.
          // See validateUnconditionally() for details.
          if (!descendUnconditionallyWhenValidating) {
            updateCur = isVisible();
          }
        }
      }
    }
    if (updateCur) {
      updateCursorImmediately();
    }
  }

  /**
   * Indicates whether valid containers should also traverse their
   * children and call the validateTree() method on them.
   *
   * Synchronization: TreeLock.
   *
   * The field is allowed to be static as long as the TreeLock itself is
   * static.
   *
   * @see #validateUnconditionally()
   */
  private static boolean descendUnconditionallyWhenValidating = false;

  /**
   * Unconditionally validate the component hierarchy.
   */
  final void validateUnconditionally() {
    boolean updateCur = false;
    synchronized (getTreeLock()) {
      descendUnconditionallyWhenValidating = true;

      validate();
      if (peer instanceof ContainerPeer) {
        updateCur = isVisible();
      }

      descendUnconditionallyWhenValidating = false;
    }
    if (updateCur) {
      updateCursorImmediately();
    }
  }

  /**
   * Recursively descends the container tree and recomputes the
   * layout for any subtrees marked as needing it (those marked as
   * invalid).  Synchronization should be provided by the method
   * that calls this one:  <code>validate</code>.
   *
   * @see #doLayout
   * @see #validate
   */
  protected void validateTree() {
    checkTreeLock();
    if (!isValid() || descendUnconditionallyWhenValidating) {
      if (peer instanceof ContainerPeer) {
        ((ContainerPeer) peer).beginLayout();
      }
      if (!isValid()) {
        doLayout();
      }
      for (int i = 0; i < component.size(); i++) {
        Component comp = component.get(i);
        if ((comp instanceof Container)
            && !(comp instanceof Window)
            && (!comp.isValid() ||
            descendUnconditionallyWhenValidating)) {
          ((Container) comp).validateTree();
        } else {
          comp.validate();
        }
      }
      if (peer instanceof ContainerPeer) {
        ((ContainerPeer) peer).endLayout();
      }
    }
    super.validate();
  }

  /**
   * Recursively descends the container tree and invalidates all
   * contained components.
   */
  void invalidateTree() {
    synchronized (getTreeLock()) {
      for (int i = 0; i < component.size(); i++) {
        Component comp = component.get(i);
        if (comp instanceof Container) {
          ((Container) comp).invalidateTree();
        } else {
          comp.invalidateIfValid();
        }
      }
      invalidateIfValid();
    }
  }

  /**
   * Sets the font of this container.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy.
   *
   * @param f The font to become this container's font.
   * @see Component#getFont
   * @see #invalidate
   * @since JDK1.0
   */
  public void setFont(Font f) {
    boolean shouldinvalidate = false;

    Font oldfont = getFont();
    super.setFont(f);
    Font newfont = getFont();
    if (newfont != oldfont && (oldfont == null ||
        !oldfont.equals(newfont))) {
      invalidateTree();
    }
  }

  /**
   * Returns the preferred size of this container.  If the preferred size has
   * not been set explicitly by {@link Component#setPreferredSize(Dimension)}
   * and this {@code Container} has a {@code non-null} {@link LayoutManager},
   * then {@link LayoutManager#preferredLayoutSize(Container)}
   * is used to calculate the preferred size.
   *
   * <p>Note: some implementations may cache the value returned from the
   * {@code LayoutManager}.  Implementations that cache need not invoke
   * {@code preferredLayoutSize} on the {@code LayoutManager} every time
   * this method is invoked, rather the {@code LayoutManager} will only
   * be queried after the {@code Container} becomes invalid.
   *
   * @return an instance of <code>Dimension</code> that represents the preferred size of this
   * container.
   * @see #getMinimumSize
   * @see #getMaximumSize
   * @see #getLayout
   * @see LayoutManager#preferredLayoutSize(Container)
   * @see Component#getPreferredSize
   */
  public Dimension getPreferredSize() {
    return preferredSize();
  }

  /**
   * @deprecated As of JDK version 1.1, replaced by <code>getPreferredSize()</code>.
   */
  @Deprecated
  public Dimension preferredSize() {
        /* Avoid grabbing the lock if a reasonable cached size value
         * is available.
         */
    Dimension dim = prefSize;
    if (dim == null || !(isPreferredSizeSet() || isValid())) {
      synchronized (getTreeLock()) {
        prefSize = (layoutMgr != null) ?
            layoutMgr.preferredLayoutSize(this) :
            super.preferredSize();
        dim = prefSize;
      }
    }
    if (dim != null) {
      return new Dimension(dim);
    } else {
      return dim;
    }
  }

  /**
   * Returns the minimum size of this container.  If the minimum size has
   * not been set explicitly by {@link Component#setMinimumSize(Dimension)}
   * and this {@code Container} has a {@code non-null} {@link LayoutManager},
   * then {@link LayoutManager#minimumLayoutSize(Container)}
   * is used to calculate the minimum size.
   *
   * <p>Note: some implementations may cache the value returned from the
   * {@code LayoutManager}.  Implementations that cache need not invoke
   * {@code minimumLayoutSize} on the {@code LayoutManager} every time
   * this method is invoked, rather the {@code LayoutManager} will only
   * be queried after the {@code Container} becomes invalid.
   *
   * @return an instance of <code>Dimension</code> that represents the minimum size of this
   * container.
   * @see #getPreferredSize
   * @see #getMaximumSize
   * @see #getLayout
   * @see LayoutManager#minimumLayoutSize(Container)
   * @see Component#getMinimumSize
   * @since JDK1.1
   */
  public Dimension getMinimumSize() {
    return minimumSize();
  }

  /**
   * @deprecated As of JDK version 1.1, replaced by <code>getMinimumSize()</code>.
   */
  @Deprecated
  public Dimension minimumSize() {
        /* Avoid grabbing the lock if a reasonable cached size value
         * is available.
         */
    Dimension dim = minSize;
    if (dim == null || !(isMinimumSizeSet() || isValid())) {
      synchronized (getTreeLock()) {
        minSize = (layoutMgr != null) ?
            layoutMgr.minimumLayoutSize(this) :
            super.minimumSize();
        dim = minSize;
      }
    }
    if (dim != null) {
      return new Dimension(dim);
    } else {
      return dim;
    }
  }

  /**
   * Returns the maximum size of this container.  If the maximum size has
   * not been set explicitly by {@link Component#setMaximumSize(Dimension)}
   * and the {@link LayoutManager} installed on this {@code Container}
   * is an instance of {@link LayoutManager2}, then
   * {@link LayoutManager2#maximumLayoutSize(Container)}
   * is used to calculate the maximum size.
   *
   * <p>Note: some implementations may cache the value returned from the
   * {@code LayoutManager2}.  Implementations that cache need not invoke
   * {@code maximumLayoutSize} on the {@code LayoutManager2} every time
   * this method is invoked, rather the {@code LayoutManager2} will only
   * be queried after the {@code Container} becomes invalid.
   *
   * @return an instance of <code>Dimension</code> that represents the maximum size of this
   * container.
   * @see #getPreferredSize
   * @see #getMinimumSize
   * @see #getLayout
   * @see LayoutManager2#maximumLayoutSize(Container)
   * @see Component#getMaximumSize
   */
  public Dimension getMaximumSize() {
        /* Avoid grabbing the lock if a reasonable cached size value
         * is available.
         */
    Dimension dim = maxSize;
    if (dim == null || !(isMaximumSizeSet() || isValid())) {
      synchronized (getTreeLock()) {
        if (layoutMgr instanceof LayoutManager2) {
          LayoutManager2 lm = (LayoutManager2) layoutMgr;
          maxSize = lm.maximumLayoutSize(this);
        } else {
          maxSize = super.getMaximumSize();
        }
        dim = maxSize;
      }
    }
    if (dim != null) {
      return new Dimension(dim);
    } else {
      return dim;
    }
  }

  /**
   * Returns the alignment along the x axis.  This specifies how
   * the component would like to be aligned relative to other
   * components.  The value should be a number between 0 and 1
   * where 0 represents alignment along the origin, 1 is aligned
   * the furthest away from the origin, 0.5 is centered, etc.
   */
  public float getAlignmentX() {
    float xAlign;
    if (layoutMgr instanceof LayoutManager2) {
      synchronized (getTreeLock()) {
        LayoutManager2 lm = (LayoutManager2) layoutMgr;
        xAlign = lm.getLayoutAlignmentX(this);
      }
    } else {
      xAlign = super.getAlignmentX();
    }
    return xAlign;
  }

  /**
   * Returns the alignment along the y axis.  This specifies how
   * the component would like to be aligned relative to other
   * components.  The value should be a number between 0 and 1
   * where 0 represents alignment along the origin, 1 is aligned
   * the furthest away from the origin, 0.5 is centered, etc.
   */
  public float getAlignmentY() {
    float yAlign;
    if (layoutMgr instanceof LayoutManager2) {
      synchronized (getTreeLock()) {
        LayoutManager2 lm = (LayoutManager2) layoutMgr;
        yAlign = lm.getLayoutAlignmentY(this);
      }
    } else {
      yAlign = super.getAlignmentY();
    }
    return yAlign;
  }

  /**
   * Paints the container. This forwards the paint to any lightweight
   * components that are children of this container. If this method is
   * reimplemented, super.paint(g) should be called so that lightweight
   * components are properly rendered. If a child component is entirely
   * clipped by the current clipping setting in g, paint() will not be
   * forwarded to that child.
   *
   * @param g the specified Graphics window
   * @see Component#update(Graphics)
   */
  public void paint(Graphics g) {
    if (isShowing()) {
      synchronized (getObjectLock()) {
        if (printing) {
          if (printingThreads.contains(Thread.currentThread())) {
            return;
          }
        }
      }

      // The container is showing on screen and
      // this paint() is not called from print().
      // Paint self and forward the paint to lightweight subcomponents.

      // super.paint(); -- Don't bother, since it's a NOP.

      GraphicsCallback.PaintCallback.getInstance().
          runComponents(getComponentsSync(), g, GraphicsCallback.LIGHTWEIGHTS);
    }
  }

  /**
   * Updates the container.  This forwards the update to any lightweight
   * components that are children of this container.  If this method is
   * reimplemented, super.update(g) should be called so that lightweight
   * components are properly rendered.  If a child component is entirely
   * clipped by the current clipping setting in g, update() will not be
   * forwarded to that child.
   *
   * @param g the specified Graphics window
   * @see Component#update(Graphics)
   */
  public void update(Graphics g) {
    if (isShowing()) {
      if (!(peer instanceof LightweightPeer)) {
        g.clearRect(0, 0, width, height);
      }
      paint(g);
    }
  }

  /**
   * Prints the container. This forwards the print to any lightweight
   * components that are children of this container. If this method is
   * reimplemented, super.print(g) should be called so that lightweight
   * components are properly rendered. If a child component is entirely
   * clipped by the current clipping setting in g, print() will not be
   * forwarded to that child.
   *
   * @param g the specified Graphics window
   * @see Component#update(Graphics)
   */
  public void print(Graphics g) {
    if (isShowing()) {
      Thread t = Thread.currentThread();
      try {
        synchronized (getObjectLock()) {
          if (printingThreads == null) {
            printingThreads = new HashSet<>();
          }
          printingThreads.add(t);
          printing = true;
        }
        super.print(g);  // By default, Component.print() calls paint()
      } finally {
        synchronized (getObjectLock()) {
          printingThreads.remove(t);
          printing = !printingThreads.isEmpty();
        }
      }

      GraphicsCallback.PrintCallback.getInstance().
          runComponents(getComponentsSync(), g, GraphicsCallback.LIGHTWEIGHTS);
    }
  }

  /**
   * Paints each of the components in this container.
   *
   * @param g the graphics context.
   * @see Component#paint
   * @see Component#paintAll
   */
  public void paintComponents(Graphics g) {
    if (isShowing()) {
      GraphicsCallback.PaintAllCallback.getInstance().
          runComponents(getComponentsSync(), g, GraphicsCallback.TWO_PASSES);
    }
  }

  /**
   * Simulates the peer callbacks into java.awt for printing of
   * lightweight Containers.
   *
   * @param g the graphics context to use for printing.
   * @see Component#printAll
   * @see #printComponents
   */
  void lightweightPaint(Graphics g) {
    super.lightweightPaint(g);
    paintHeavyweightComponents(g);
  }

  /**
   * Prints all the heavyweight subcomponents.
   */
  void paintHeavyweightComponents(Graphics g) {
    if (isShowing()) {
      GraphicsCallback.PaintHeavyweightComponentsCallback.getInstance().
          runComponents(getComponentsSync(), g,
              GraphicsCallback.LIGHTWEIGHTS | GraphicsCallback.HEAVYWEIGHTS);
    }
  }

  /**
   * Prints each of the components in this container.
   *
   * @param g the graphics context.
   * @see Component#print
   * @see Component#printAll
   */
  public void printComponents(Graphics g) {
    if (isShowing()) {
      GraphicsCallback.PrintAllCallback.getInstance().
          runComponents(getComponentsSync(), g, GraphicsCallback.TWO_PASSES);
    }
  }

  /**
   * Simulates the peer callbacks into java.awt for printing of
   * lightweight Containers.
   *
   * @param g the graphics context to use for printing.
   * @see Component#printAll
   * @see #printComponents
   */
  void lightweightPrint(Graphics g) {
    super.lightweightPrint(g);
    printHeavyweightComponents(g);
  }

  /**
   * Prints all the heavyweight subcomponents.
   */
  void printHeavyweightComponents(Graphics g) {
    if (isShowing()) {
      GraphicsCallback.PrintHeavyweightComponentsCallback.getInstance().
          runComponents(getComponentsSync(), g,
              GraphicsCallback.LIGHTWEIGHTS | GraphicsCallback.HEAVYWEIGHTS);
    }
  }

  /**
   * Adds the specified container listener to receive container events
   * from this container.
   * If l is null, no exception is thrown and no action is performed.
   * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
   * >AWT Threading Issues</a> for details on AWT's threading model.
   *
   * @param l the container listener
   * @see #removeContainerListener
   * @see #getContainerListeners
   */
  public synchronized void addContainerListener(ContainerListener l) {
    if (l == null) {
      return;
    }
    containerListener = AWTEventMulticaster.add(containerListener, l);
    newEventsOnly = true;
  }

  /**
   * Removes the specified container listener so it no longer receives
   * container events from this container.
   * If l is null, no exception is thrown and no action is performed.
   * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
   * >AWT Threading Issues</a> for details on AWT's threading model.
   *
   * @param l the container listener
   * @see #addContainerListener
   * @see #getContainerListeners
   */
  public synchronized void removeContainerListener(ContainerListener l) {
    if (l == null) {
      return;
    }
    containerListener = AWTEventMulticaster.remove(containerListener, l);
  }

  /**
   * Returns an array of all the container listeners
   * registered on this container.
   *
   * @return all of this container's <code>ContainerListener</code>s or an empty array if no
   * container listeners are currently registered
   * @see #addContainerListener
   * @see #removeContainerListener
   * @since 1.4
   */
  public synchronized ContainerListener[] getContainerListeners() {
    return getListeners(ContainerListener.class);
  }

  /**
   * Returns an array of all the objects currently registered as <code><em>Foo</em>Listener</code>s
   * upon this <code>Container</code>. <code><em>Foo</em>Listener</code>s are registered using the
   * <code>add<em>Foo</em>Listener</code> method.
   *
   * <p> You can specify the <code>listenerType</code> argument with a class literal, such as
   * <code><em>Foo</em>Listener.class</code>. For example, you can query a <code>Container</code>
   * <code>c</code> for its container listeners with the following code:
   *
   * <pre>ContainerListener[] cls = (ContainerListener[])(c.getListeners(ContainerListener.class));</pre>
   *
   * If no such listeners exist, this method returns an empty array.
   *
   * @param listenerType the type of listeners requested; this parameter should specify an interface
   * that descends from <code>java.util.EventListener</code>
   * @return an array of all objects registered as <code><em>Foo</em>Listener</code>s on this
   * container, or an empty array if no such listeners have been added
   * @throws ClassCastException if <code>listenerType</code> doesn't specify a class or interface
   * that implements <code>java.util.EventListener</code>
   * @throws NullPointerException if {@code listenerType} is {@code null}
   * @see #getContainerListeners
   * @since 1.3
   */
  public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
    EventListener l = null;
    if (listenerType == ContainerListener.class) {
      l = containerListener;
    } else {
      return super.getListeners(listenerType);
    }
    return AWTEventMulticaster.getListeners(l, listenerType);
  }

  // REMIND: remove when filtering is done at lower level
  boolean eventEnabled(AWTEvent e) {
    int id = e.getID();

    if (id == ContainerEvent.COMPONENT_ADDED ||
        id == ContainerEvent.COMPONENT_REMOVED) {
      if ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
          containerListener != null) {
        return true;
      }
      return false;
    }
    return super.eventEnabled(e);
  }

  /**
   * Processes events on this container. If the event is a
   * <code>ContainerEvent</code>, it invokes the
   * <code>processContainerEvent</code> method, else it invokes
   * its superclass's <code>processEvent</code>.
   * <p>Note that if the event parameter is <code>null</code>
   * the behavior is unspecified and may result in an
   * exception.
   *
   * @param e the event
   */
  protected void processEvent(AWTEvent e) {
    if (e instanceof ContainerEvent) {
      processContainerEvent((ContainerEvent) e);
      return;
    }
    super.processEvent(e);
  }

  /**
   * Processes container events occurring on this container by
   * dispatching them to any registered ContainerListener objects.
   * NOTE: This method will not be called unless container events
   * are enabled for this component; this happens when one of the
   * following occurs:
   * <ul>
   * <li>A ContainerListener object is registered via
   * <code>addContainerListener</code>
   * <li>Container events are enabled via <code>enableEvents</code>
   * </ul>
   * <p>Note that if the event parameter is <code>null</code>
   * the behavior is unspecified and may result in an
   * exception.
   *
   * @param e the container event
   * @see Component#enableEvents
   */
  protected void processContainerEvent(ContainerEvent e) {
    ContainerListener listener = containerListener;
    if (listener != null) {
      switch (e.getID()) {
        case ContainerEvent.COMPONENT_ADDED:
          listener.componentAdded(e);
          break;
        case ContainerEvent.COMPONENT_REMOVED:
          listener.componentRemoved(e);
          break;
      }
    }
  }

  /*
     * Dispatches an event to this component or one of its sub components.
     * Create ANCESTOR_RESIZED and ANCESTOR_MOVED events in response to
     * COMPONENT_RESIZED and COMPONENT_MOVED events. We have to do this
     * here instead of in processComponentEvent because ComponentEvents
     * may not be enabled for this Container.
     * @param e the event
     */
  void dispatchEventImpl(AWTEvent e) {
    if ((dispatcher != null) && dispatcher.dispatchEvent(e)) {
      // event was sent to a lightweight component.  The
      // native-produced event sent to the native container
      // must be properly disposed of by the peer, so it
      // gets forwarded.  If the native host has been removed
      // as a result of the sending the lightweight event,
      // the peer reference will be null.
      e.consume();
      if (peer != null) {
        peer.handleEvent(e);
      }
      return;
    }

    super.dispatchEventImpl(e);

    synchronized (getTreeLock()) {
      switch (e.getID()) {
        case ComponentEvent.COMPONENT_RESIZED:
          createChildHierarchyEvents(HierarchyEvent.ANCESTOR_RESIZED, 0,
              Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
          break;
        case ComponentEvent.COMPONENT_MOVED:
          createChildHierarchyEvents(HierarchyEvent.ANCESTOR_MOVED, 0,
              Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
          break;
        default:
          break;
      }
    }
  }

  /*
     * Dispatches an event to this component, without trying to forward
     * it to any subcomponents
     * @param e the event
     */
  void dispatchEventToSelf(AWTEvent e) {
    super.dispatchEventImpl(e);
  }

  /**
   * Fetchs the top-most (deepest) lightweight component that is interested
   * in receiving mouse events.
   */
  Component getMouseEventTarget(int x, int y, boolean includeSelf) {
    return getMouseEventTarget(x, y, includeSelf,
        MouseEventTargetFilter.FILTER,
        !SEARCH_HEAVYWEIGHTS);
  }

  /**
   * Fetches the top-most (deepest) component to receive SunDropTargetEvents.
   */
  Component getDropTargetEventTarget(int x, int y, boolean includeSelf) {
    return getMouseEventTarget(x, y, includeSelf,
        DropTargetEventTargetFilter.FILTER,
        SEARCH_HEAVYWEIGHTS);
  }

  /**
   * A private version of getMouseEventTarget which has two additional
   * controllable behaviors. This method searches for the top-most
   * descendant of this container that contains the given coordinates
   * and is accepted by the given filter. The search will be constrained to
   * lightweight descendants if the last argument is <code>false</code>.
   *
   * @param filter EventTargetFilter instance to determine whether the given component is a valid
   * target for this event.
   * @param searchHeavyweights if <code>false</code>, the method will bypass heavyweight components
   * during the search.
   */
  private Component getMouseEventTarget(int x, int y, boolean includeSelf,
      EventTargetFilter filter,
      boolean searchHeavyweights) {
    Component comp = null;
    if (searchHeavyweights) {
      comp = getMouseEventTargetImpl(x, y, includeSelf, filter,
          SEARCH_HEAVYWEIGHTS,
          searchHeavyweights);
    }

    if (comp == null || comp == this) {
      comp = getMouseEventTargetImpl(x, y, includeSelf, filter,
          !SEARCH_HEAVYWEIGHTS,
          searchHeavyweights);
    }

    return comp;
  }

  /**
   * A private version of getMouseEventTarget which has three additional
   * controllable behaviors. This method searches for the top-most
   * descendant of this container that contains the given coordinates
   * and is accepted by the given filter. The search will be constrained to
   * descendants of only lightweight children or only heavyweight children
   * of this container depending on searchHeavyweightChildren. The search will
   * be constrained to only lightweight descendants of the searched children
   * of this container if searchHeavyweightDescendants is <code>false</code>.
   *
   * @param filter EventTargetFilter instance to determine whether the selected component is a valid
   * target for this event.
   * @param searchHeavyweightChildren if <code>true</code>, the method will bypass immediate
   * lightweight children during the search. If <code>false</code>, the methods will bypass
   * immediate heavyweight children during the search.
   * @param searchHeavyweightDescendants if <code>false</code>, the method will bypass heavyweight
   * descendants which are not immediate children during the search. If <code>true</code>, the
   * method will traverse both lightweight and heavyweight descendants during the search.
   */
  private Component getMouseEventTargetImpl(int x, int y, boolean includeSelf,
      EventTargetFilter filter,
      boolean searchHeavyweightChildren,
      boolean searchHeavyweightDescendants) {
    synchronized (getTreeLock()) {

      for (int i = 0; i < component.size(); i++) {
        Component comp = component.get(i);
        if (comp != null && comp.visible &&
            ((!searchHeavyweightChildren &&
                comp.peer instanceof LightweightPeer) ||
                (searchHeavyweightChildren &&
                    !(comp.peer instanceof LightweightPeer))) &&
            comp.contains(x - comp.x, y - comp.y)) {

          // found a component that intersects the point, see if there
          // is a deeper possibility.
          if (comp instanceof Container) {
            Container child = (Container) comp;
            Component deeper = child.getMouseEventTarget(
                x - child.x,
                y - child.y,
                includeSelf,
                filter,
                searchHeavyweightDescendants);
            if (deeper != null) {
              return deeper;
            }
          } else {
            if (filter.accept(comp)) {
              // there isn't a deeper target, but this component
              // is a target
              return comp;
            }
          }
        }
      }

      boolean isPeerOK;
      boolean isMouseOverMe;

      isPeerOK = (peer instanceof LightweightPeer) || includeSelf;
      isMouseOverMe = contains(x, y);

      // didn't find a child target, return this component if it's
      // a possible target
      if (isMouseOverMe && isPeerOK && filter.accept(this)) {
        return this;
      }
      // no possible target
      return null;
    }
  }

  static interface EventTargetFilter {

    boolean accept(final Component comp);
  }

  static class MouseEventTargetFilter implements EventTargetFilter {

    static final EventTargetFilter FILTER = new MouseEventTargetFilter();

    private MouseEventTargetFilter() {
    }

    public boolean accept(final Component comp) {
      return (comp.eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0
          || (comp.eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0
          || (comp.eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0
          || comp.mouseListener != null
          || comp.mouseMotionListener != null
          || comp.mouseWheelListener != null;
    }
  }

  static class DropTargetEventTargetFilter implements EventTargetFilter {

    static final EventTargetFilter FILTER = new DropTargetEventTargetFilter();

    private DropTargetEventTargetFilter() {
    }

    public boolean accept(final Component comp) {
      DropTarget dt = comp.getDropTarget();
      return dt != null && dt.isActive();
    }
  }

  /**
   * This is called by lightweight components that want the containing
   * windowed parent to enable some kind of events on their behalf.
   * This is needed for events that are normally only dispatched to
   * windows to be accepted so that they can be forwarded downward to
   * the lightweight component that has enabled them.
   */
  void proxyEnableEvents(long events) {
    if (peer instanceof LightweightPeer) {
      // this container is lightweight.... continue sending it
      // upward.
      if (parent != null) {
        parent.proxyEnableEvents(events);
      }
    } else {
      // This is a native container, so it needs to host
      // one of it's children.  If this function is called before
      // a peer has been created we don't yet have a dispatcher
      // because it has not yet been determined if this instance
      // is lightweight.
      if (dispatcher != null) {
        dispatcher.enableEvents(events);
      }
    }
  }

  /**
   * @deprecated As of JDK version 1.1, replaced by <code>dispatchEvent(AWTEvent e)</code>
   */
  @Deprecated
  public void deliverEvent(Event e) {
    Component comp = getComponentAt(e.x, e.y);
    if ((comp != null) && (comp != this)) {
      e.translate(-comp.x, -comp.y);
      comp.deliverEvent(e);
    } else {
      postEvent(e);
    }
  }

  /**
   * Locates the component that contains the x,y position.  The
   * top-most child component is returned in the case where there
   * is overlap in the components.  This is determined by finding
   * the component closest to the index 0 that claims to contain
   * the given point via Component.contains(), except that Components
   * which have native peers take precedence over those which do not
   * (i.e., lightweight Components).
   *
   * @param x the <i>x</i> coordinate
   * @param y the <i>y</i> coordinate
   * @return null if the component does not contain the position. If there is no child component at
   * the requested point and the point is within the bounds of the container the container itself is
   * returned; otherwise the top-most child is returned.
   * @see Component#contains
   * @since JDK1.1
   */
  public Component getComponentAt(int x, int y) {
    return locate(x, y);
  }

  /**
   * @deprecated As of JDK version 1.1, replaced by <code>getComponentAt(int, int)</code>.
   */
  @Deprecated
  public Component locate(int x, int y) {
    if (!contains(x, y)) {
      return null;
    }
    Component lightweight = null;
    synchronized (getTreeLock()) {
      // Optimized version of two passes:
      // see comment in sun.awt.SunGraphicsCallback
      for (final Component comp : component) {
        if (comp.contains(x - comp.x, y - comp.y)) {
          if (!comp.isLightweight()) {
            // return heavyweight component as soon as possible
            return comp;
          }
          if (lightweight == null) {
            // save and return later the first lightweight component
            lightweight = comp;
          }
        }
      }
    }
    return lightweight != null ? lightweight : this;
  }

  /**
   * Gets the component that contains the specified point.
   *
   * @param p the point.
   * @return returns the component that contains the point, or <code>null</code> if the component
   * does not contain the point.
   * @see Component#contains
   * @since JDK1.1
   */
  public Component getComponentAt(Point p) {
    return getComponentAt(p.x, p.y);
  }

  /**
   * Returns the position of the mouse pointer in this <code>Container</code>'s
   * coordinate space if the <code>Container</code> is under the mouse pointer,
   * otherwise returns <code>null</code>.
   * This method is similar to {@link Component#getMousePosition()} with the exception
   * that it can take the <code>Container</code>'s children into account.
   * If <code>allowChildren</code> is <code>false</code>, this method will return
   * a non-null value only if the mouse pointer is above the <code>Container</code>
   * directly, not above the part obscured by children.
   * If <code>allowChildren</code> is <code>true</code>, this method returns
   * a non-null value if the mouse pointer is above <code>Container</code> or any
   * of its descendants.
   *
   * @param allowChildren true if children should be taken into account
   * @return mouse coordinates relative to this <code>Component</code>, or null
   * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true
   * @see Component#getMousePosition
   * @since 1.5
   */
  public Point getMousePosition(boolean allowChildren) throws HeadlessException {
    if (GraphicsEnvironment.isHeadless()) {
      throw new HeadlessException();
    }
    PointerInfo pi = java.security.AccessController.doPrivileged(
        new java.security.PrivilegedAction<PointerInfo>() {
          public PointerInfo run() {
            return MouseInfo.getPointerInfo();
          }
        }
    );
    synchronized (getTreeLock()) {
      Component inTheSameWindow = findUnderMouseInWindow(pi);
      if (isSameOrAncestorOf(inTheSameWindow, allowChildren)) {
        return pointRelativeToComponent(pi.getLocation());
      }
      return null;
    }
  }

  boolean isSameOrAncestorOf(Component comp, boolean allowChildren) {
    return this == comp || (allowChildren && isParentOf(comp));
  }

  /**
   * Locates the visible child component that contains the specified
   * position.  The top-most child component is returned in the case
   * where there is overlap in the components.  If the containing child
   * component is a Container, this method will continue searching for
   * the deepest nested child component.  Components which are not
   * visible are ignored during the search.<p>
   *
   * The findComponentAt method is different from getComponentAt in
   * that getComponentAt only searches the Container's immediate
   * children; if the containing component is a Container,
   * findComponentAt will search that child to find a nested component.
   *
   * @param x the <i>x</i> coordinate
   * @param y the <i>y</i> coordinate
   * @return null if the component does not contain the position. If there is no child component at
   * the requested point and the point is within the bounds of the container the container itself is
   * returned.
   * @see Component#contains
   * @see #getComponentAt
   * @since 1.2
   */
  public Component findComponentAt(int x, int y) {
    return findComponentAt(x, y, true);
  }

  /**
   * Private version of findComponentAt which has a controllable
   * behavior. Setting 'ignoreEnabled' to 'false' bypasses disabled
   * Components during the search. This behavior is used by the
   * lightweight cursor support in sun.awt.GlobalCursorManager.
   *
   * The addition of this feature is temporary, pending the
   * adoption of new, public API which exports this feature.
   */
  final Component findComponentAt(int x, int y, boolean ignoreEnabled) {
    synchronized (getTreeLock()) {
      if (isRecursivelyVisible()) {
        return findComponentAtImpl(x, y, ignoreEnabled);
      }
    }
    return null;
  }

  final Component findComponentAtImpl(int x, int y, boolean ignoreEnabled) {
    // checkTreeLock(); commented for a performance reason

    if (!(contains(x, y) && visible && (ignoreEnabled || enabled))) {
      return null;
    }
    Component lightweight = null;
    // Optimized version of two passes:
    // see comment in sun.awt.SunGraphicsCallback
    for (final Component comp : component) {
      final int x1 = x - comp.x;
      final int y1 = y - comp.y;
      if (!comp.contains(x1, y1)) {
        continue; // fast path
      }
      if (!comp.isLightweight()) {
        final Component child = getChildAt(comp, x1, y1, ignoreEnabled);
        if (child != null) {
          // return heavyweight component as soon as possible
          return child;
        }
      } else {
        if (lightweight == null) {
          // save and return later the first lightweight component
          lightweight = getChildAt(comp, x1, y1, ignoreEnabled);
        }
      }
    }
    return lightweight != null ? lightweight : this;
  }

  /**
   * Helper method for findComponentAtImpl. Finds a child component using
   * findComponentAtImpl for Container and getComponentAt for Component.
   */
  private static Component getChildAt(Component comp, int x, int y,
      boolean ignoreEnabled) {
    if (comp instanceof Container) {
      comp = ((Container) comp).findComponentAtImpl(x, y,
          ignoreEnabled);
    } else {
      comp = comp.getComponentAt(x, y);
    }
    if (comp != null && comp.visible &&
        (ignoreEnabled || comp.enabled)) {
      return comp;
    }
    return null;
  }

  /**
   * Locates the visible child component that contains the specified
   * point.  The top-most child component is returned in the case
   * where there is overlap in the components.  If the containing child
   * component is a Container, this method will continue searching for
   * the deepest nested child component.  Components which are not
   * visible are ignored during the search.<p>
   *
   * The findComponentAt method is different from getComponentAt in
   * that getComponentAt only searches the Container's immediate
   * children; if the containing component is a Container,
   * findComponentAt will search that child to find a nested component.
   *
   * @param p the point.
   * @return null if the component does not contain the position. If there is no child component at
   * the requested point and the point is within the bounds of the container the container itself is
   * returned.
   * @throws NullPointerException if {@code p} is {@code null}
   * @see Component#contains
   * @see #getComponentAt
   * @since 1.2
   */
  public Component findComponentAt(Point p) {
    return findComponentAt(p.x, p.y);
  }

  /**
   * Makes this Container displayable by connecting it to
   * a native screen resource.  Making a container displayable will
   * cause all of its children to be made displayable.
   * This method is called internally by the toolkit and should
   * not be called directly by programs.
   *
   * @see Component#isDisplayable
   * @see #removeNotify
   */
  public void addNotify() {
    synchronized (getTreeLock()) {
      // addNotify() on the children may cause proxy event enabling
      // on this instance, so we first call super.addNotify() and
      // possibly create an lightweight event dispatcher before calling
      // addNotify() on the children which may be lightweight.
      super.addNotify();
      if (!(peer instanceof LightweightPeer)) {
        dispatcher = new LightweightDispatcher(this);
      }

      // We shouldn't use iterator because of the Swing menu
      // implementation specifics:
      // the menu is being assigned as a child to JLayeredPane
      // instead of particular component so always affect
      // collection of component if menu is becoming shown or hidden.
      for (int i = 0; i < component.size(); i++) {
        component.get(i).addNotify();
      }
    }
  }

  /**
   * Makes this Container undisplayable by removing its connection
   * to its native screen resource.  Making a container undisplayable
   * will cause all of its children to be made undisplayable.
   * This method is called by the toolkit internally and should
   * not be called directly by programs.
   *
   * @see Component#isDisplayable
   * @see #addNotify
   */
  public void removeNotify() {
    synchronized (getTreeLock()) {
      // We shouldn't use iterator because of the Swing menu
      // implementation specifics:
      // the menu is being assigned as a child to JLayeredPane
      // instead of particular component so always affect
      // collection of component if menu is becoming shown or hidden.
      for (int i = component.size() - 1; i >= 0; i--) {
        Component comp = component.get(i);
        if (comp != null) {
          // Fix for 6607170.
          // We want to suppress focus change on disposal
          // of the focused component. But because of focus
          // is asynchronous, we should suppress focus change
          // on every component in case it receives native focus
          // in the process of disposal.
          comp.setAutoFocusTransferOnDisposal(false);
          comp.removeNotify();
          comp.setAutoFocusTransferOnDisposal(true);
        }
      }
      // If some of the children had focus before disposal then it still has.
      // Auto-transfer focus to the next (or previous) component if auto-transfer
      // is enabled.
      if (containsFocus() && KeyboardFocusManager.isAutoFocusTransferEnabledFor(this)) {
        if (!transferFocus(false)) {
          transferFocusBackward(true);
        }
      }
      if (dispatcher != null) {
        dispatcher.dispose();
        dispatcher = null;
      }
      super.removeNotify();
    }
  }

  /**
   * Checks if the component is contained in the component hierarchy of
   * this container.
   *
   * @param c the component
   * @return <code>true</code> if it is an ancestor; <code>false</code> otherwise.
   * @since JDK1.1
   */
  public boolean isAncestorOf(Component c) {
    Container p;
    if (c == null || ((p = c.getParent()) == null)) {
      return false;
    }
    while (p != null) {
      if (p == this) {
        return true;
      }
      p = p.getParent();
    }
    return false;
  }

    /*
     * The following code was added to support modal JInternalFrames
     * Unfortunately this code has to be added here so that we can get access to
     * some private AWT classes like SequencedEvent.
     *
     * The native container of the LW component has this field set
     * to tell it that it should block Mouse events for all LW
     * children except for the modal component.
     *
     * In the case of nested Modal components, we store the previous
     * modal component in the new modal components value of modalComp;
     */

  transient Component modalComp;
  transient AppContext modalAppContext;

  private void startLWModal() {
    // Store the app context on which this component is being shown.
    // Event dispatch thread of this app context will be sleeping until
    // we wake it by any event from hideAndDisposeHandler().
    modalAppContext = AppContext.getAppContext();

    // keep the KeyEvents from being dispatched
    // until the focus has been transfered
    long time = Toolkit.getEventQueue().getMostRecentKeyEventTime();
    Component predictedFocusOwner = (Component.isInstanceOf(this, "javax.swing.JInternalFrame"))
        ? ((javax.swing.JInternalFrame) (this)).getMostRecentFocusOwner() : null;
    if (predictedFocusOwner != null) {
      KeyboardFocusManager.getCurrentKeyboardFocusManager().
          enqueueKeyEvents(time, predictedFocusOwner);
    }
    // We have two mechanisms for blocking: 1. If we're on the
    // EventDispatchThread, start a new event pump. 2. If we're
    // on any other thread, call wait() on the treelock.
    final Container nativeContainer;
    synchronized (getTreeLock()) {
      nativeContainer = getHeavyweightContainer();
      if (nativeContainer.modalComp != null) {
        this.modalComp = nativeContainer.modalComp;
        nativeContainer.modalComp = this;
        return;
      } else {
        nativeContainer.modalComp = this;
      }
    }

    Runnable pumpEventsForHierarchy = new Runnable() {
      public void run() {
        EventDispatchThread dispatchThread =
            (EventDispatchThread) Thread.currentThread();
        dispatchThread.pumpEventsForHierarchy(
            new Conditional() {
              public boolean evaluate() {
                return ((windowClosingException == null) && (nativeContainer.modalComp != null));
              }
            }, Container.this);
      }
    };

    if (EventQueue.isDispatchThread()) {
      SequencedEvent currentSequencedEvent =
          KeyboardFocusManager.getCurrentKeyboardFocusManager().
              getCurrentSequencedEvent();
      if (currentSequencedEvent != null) {
        currentSequencedEvent.dispose();
      }

      pumpEventsForHierarchy.run();
    } else {
      synchronized (getTreeLock()) {
        Toolkit.getEventQueue().
            postEvent(new PeerEvent(this,
                pumpEventsForHierarchy,
                PeerEvent.PRIORITY_EVENT));
        while ((windowClosingException == null) &&
            (nativeContainer.modalComp != null)) {
          try {
            getTreeLock().wait();
          } catch (InterruptedException e) {
            break;
          }
        }
      }
    }
    if (windowClosingException != null) {
      windowClosingException.fillInStackTrace();
      throw windowClosingException;
    }
    if (predictedFocusOwner != null) {
      KeyboardFocusManager.getCurrentKeyboardFocusManager().
          dequeueKeyEvents(time, predictedFocusOwner);
    }
  }

  private void stopLWModal() {
    synchronized (getTreeLock()) {
      if (modalAppContext != null) {
        Container nativeContainer = getHeavyweightContainer();
        if (nativeContainer != null) {
          if (this.modalComp != null) {
            nativeContainer.modalComp = this.modalComp;
            this.modalComp = null;
            return;
          } else {
            nativeContainer.modalComp = null;
          }
        }
        // Wake up event dispatch thread on which the dialog was
        // initially shown
        SunToolkit.postEvent(modalAppContext,
            new PeerEvent(this,
                new WakingRunnable(),
                PeerEvent.PRIORITY_EVENT));
      }
      EventQueue.invokeLater(new WakingRunnable());
      getTreeLock().notifyAll();
    }
  }

  final static class WakingRunnable implements Runnable {

    public void run() {
    }
  }

    /* End of JOptionPane support code */

  /**
   * Returns a string representing the state of this <code>Container</code>.
   * This method is intended to be used only for debugging purposes, and the
   * content and format of the returned string may vary between
   * implementations. The returned string may be empty but may not be
   * <code>null</code>.
   *
   * @return the parameter string of this container
   */
  protected String paramString() {
    String str = super.paramString();
    LayoutManager layoutMgr = this.layoutMgr;
    if (layoutMgr != null) {
      str += ",layout=" + layoutMgr.getClass().getName();
    }
    return str;
  }

  /**
   * Prints a listing of this container to the specified output
   * stream. The listing starts at the specified indentation.
   * <p>
   * The immediate children of the container are printed with
   * an indentation of <code>indent+1</code>.  The children
   * of those children are printed at <code>indent+2</code>
   * and so on.
   *
   * @param out a print stream
   * @param indent the number of spaces to indent
   * @throws NullPointerException if {@code out} is {@code null}
   * @see Component#list(java.io.PrintStream, int)
   * @since JDK1.0
   */
  public void list(PrintStream out, int indent) {
    super.list(out, indent);
    synchronized (getTreeLock()) {
      for (int i = 0; i < component.size(); i++) {
        Component comp = component.get(i);
        if (comp != null) {
          comp.list(out, indent + 1);
        }
      }
    }
  }

  /**
   * Prints out a list, starting at the specified indentation,
   * to the specified print writer.
   * <p>
   * The immediate children of the container are printed with
   * an indentation of <code>indent+1</code>.  The children
   * of those children are printed at <code>indent+2</code>
   * and so on.
   *
   * @param out a print writer
   * @param indent the number of spaces to indent
   * @throws NullPointerException if {@code out} is {@code null}
   * @see Component#list(java.io.PrintWriter, int)
   * @since JDK1.1
   */
  public void list(PrintWriter out, int indent) {
    super.list(out, indent);
    synchronized (getTreeLock()) {
      for (int i = 0; i < component.size(); i++) {
        Component comp = component.get(i);
        if (comp != null) {
          comp.list(out, indent + 1);
        }
      }
    }
  }

  /**
   * Sets the focus traversal keys for a given traversal operation for this
   * Container.
   * <p>
   * The default values for a Container's focus traversal keys are
   * implementation-dependent. Sun recommends that all implementations for a
   * particular native platform use the same default values. The
   * recommendations for Windows and Unix are listed below. These
   * recommendations are used in the Sun AWT implementations.
   *
   * <table border=1 summary="Recommended default values for a Container's focus traversal keys">
   * <tr>
   * <th>Identifier</th>
   * <th>Meaning</th>
   * <th>Default</th>
   * </tr>
   * <tr>
   * <td>KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS</td>
   * <td>Normal forward keyboard traversal</td>
   * <td>TAB on KEY_PRESSED, CTRL-TAB on KEY_PRESSED</td>
   * </tr>
   * <tr>
   * <td>KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS</td>
   * <td>Normal reverse keyboard traversal</td>
   * <td>SHIFT-TAB on KEY_PRESSED, CTRL-SHIFT-TAB on KEY_PRESSED</td>
   * </tr>
   * <tr>
   * <td>KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS</td>
   * <td>Go up one focus traversal cycle</td>
   * <td>none</td>
   * </tr>
   * <tr>
   * <td>KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS<td>
   * <td>Go down one focus traversal cycle</td>
   * <td>none</td>
   * </tr>
   * </table>
   *
   * To disable a traversal key, use an empty Set; Collections.EMPTY_SET is
   * recommended.
   * <p>
   * Using the AWTKeyStroke API, client code can specify on which of two
   * specific KeyEvents, KEY_PRESSED or KEY_RELEASED, the focus traversal
   * operation will occur. Regardless of which KeyEvent is specified,
   * however, all KeyEvents related to the focus traversal key, including the
   * associated KEY_TYPED event, will be consumed, and will not be dispatched
   * to any Container. It is a runtime error to specify a KEY_TYPED event as
   * mapping to a focus traversal operation, or to map the same event to
   * multiple default focus traversal operations.
   * <p>
   * If a value of null is specified for the Set, this Container inherits the
   * Set from its parent. If all ancestors of this Container have null
   * specified for the Set, then the current KeyboardFocusManager's default
   * Set is used.
   * <p>
   * This method may throw a {@code ClassCastException} if any {@code Object}
   * in {@code keystrokes} is not an {@code AWTKeyStroke}.
   *
   * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
   * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
   * @param keystrokes the Set of AWTKeyStroke for the specified operation
   * @throws IllegalArgumentException if id is not one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
   * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
   * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, or if keystrokes contains null, or if any
   * keystroke represents a KEY_TYPED event, or if any keystroke already maps to another focus
   * traversal operation for this Container
   * @beaninfo bound: true
   * @see #getFocusTraversalKeys
   * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
   * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
   * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
   * @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS
   * @since 1.4
   */
  public void setFocusTraversalKeys(int id,
      Set<? extends AWTKeyStroke> keystrokes) {
    if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
      throw new IllegalArgumentException("invalid focus traversal key identifier");
    }

    // Don't call super.setFocusTraversalKey. The Component parameter check
    // does not allow DOWN_CYCLE_TRAVERSAL_KEYS, but we do.
    setFocusTraversalKeys_NoIDCheck(id, keystrokes);
  }

  /**
   * Returns the Set of focus traversal keys for a given traversal operation
   * for this Container. (See
   * <code>setFocusTraversalKeys</code> for a full description of each key.)
   * <p>
   * If a Set of traversal keys has not been explicitly defined for this
   * Container, then this Container's parent's Set is returned. If no Set
   * has been explicitly defined for any of this Container's ancestors, then
   * the current KeyboardFocusManager's default Set is returned.
   *
   * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
   * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
   * @return the Set of AWTKeyStrokes for the specified operation. The Set will be unmodifiable, and
   * may be empty. null will never be returned.
   * @throws IllegalArgumentException if id is not one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
   * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
   * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
   * @see #setFocusTraversalKeys
   * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
   * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
   * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
   * @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS
   * @since 1.4
   */
  public Set<AWTKeyStroke> getFocusTraversalKeys(int id) {
    if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
      throw new IllegalArgumentException("invalid focus traversal key identifier");
    }

    // Don't call super.getFocusTraversalKey. The Component parameter check
    // does not allow DOWN_CYCLE_TRAVERSAL_KEY, but we do.
    return getFocusTraversalKeys_NoIDCheck(id);
  }

  /**
   * Returns whether the Set of focus traversal keys for the given focus
   * traversal operation has been explicitly defined for this Container. If
   * this method returns <code>false</code>, this Container is inheriting the
   * Set from an ancestor, or from the current KeyboardFocusManager.
   *
   * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
   * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
   * @return <code>true</code> if the the Set of focus traversal keys for the given focus traversal
   * operation has been explicitly defined for this Component; <code>false</code> otherwise.
   * @throws IllegalArgumentException if id is not one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
   * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
   * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
   * @since 1.4
   */
  public boolean areFocusTraversalKeysSet(int id) {
    if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
      throw new IllegalArgumentException("invalid focus traversal key identifier");
    }

    return (focusTraversalKeys != null && focusTraversalKeys[id] != null);
  }

  /**
   * Returns whether the specified Container is the focus cycle root of this
   * Container's focus traversal cycle. Each focus traversal cycle has only
   * a single focus cycle root and each Container which is not a focus cycle
   * root belongs to only a single focus traversal cycle. Containers which
   * are focus cycle roots belong to two cycles: one rooted at the Container
   * itself, and one rooted at the Container's nearest focus-cycle-root
   * ancestor. This method will return <code>true</code> for both such
   * Containers in this case.
   *
   * @param container the Container to be tested
   * @return <code>true</code> if the specified Container is a focus-cycle- root of this Container;
   * <code>false</code> otherwise
   * @see #isFocusCycleRoot()
   * @since 1.4
   */
  public boolean isFocusCycleRoot(Container container) {
    if (isFocusCycleRoot() && container == this) {
      return true;
    } else {
      return super.isFocusCycleRoot(container);
    }
  }

  private Container findTraversalRoot() {
    // I potentially have two roots, myself and my root parent
    // If I am the current root, then use me
    // If none of my parents are roots, then use me
    // If my root parent is the current root, then use my root parent
    // If neither I nor my root parent is the current root, then
    // use my root parent (a guess)

    Container currentFocusCycleRoot = KeyboardFocusManager.
        getCurrentKeyboardFocusManager().getCurrentFocusCycleRoot();
    Container root;

    if (currentFocusCycleRoot == this) {
      root = this;
    } else {
      root = getFocusCycleRootAncestor();
      if (root == null) {
        root = this;
      }
    }

    if (root != currentFocusCycleRoot) {
      KeyboardFocusManager.getCurrentKeyboardFocusManager().
          setGlobalCurrentFocusCycleRootPriv(root);
    }
    return root;
  }

  final boolean containsFocus() {
    final Component focusOwner = KeyboardFocusManager.
        getCurrentKeyboardFocusManager().getFocusOwner();
    return isParentOf(focusOwner);
  }

  /**
   * Check if this component is the child of this container or its children.
   * Note: this function acquires treeLock
   * Note: this function traverses children tree only in one Window.
   *
   * @param comp a component in test, must not be null
   */
  private boolean isParentOf(Component comp) {
    synchronized (getTreeLock()) {
      while (comp != null && comp != this && !(comp instanceof Window)) {
        comp = comp.getParent();
      }
      return (comp == this);
    }
  }

  void clearMostRecentFocusOwnerOnHide() {
    boolean reset = false;
    Window window = null;

    synchronized (getTreeLock()) {
      window = getContainingWindow();
      if (window != null) {
        Component comp = KeyboardFocusManager.getMostRecentFocusOwner(window);
        reset = ((comp == this) || isParentOf(comp));
        // This synchronized should always be the second in a pair
        // (tree lock, KeyboardFocusManager.class)
        synchronized (KeyboardFocusManager.class) {
          Component storedComp = window.getTemporaryLostComponent();
          if (isParentOf(storedComp) || storedComp == this) {
            window.setTemporaryLostComponent(null);
          }
        }
      }
    }

    if (reset) {
      KeyboardFocusManager.setMostRecentFocusOwner(window, null);
    }
  }

  void clearCurrentFocusCycleRootOnHide() {
    KeyboardFocusManager kfm =
        KeyboardFocusManager.getCurrentKeyboardFocusManager();
    Container cont = kfm.getCurrentFocusCycleRoot();

    if (cont == this || isParentOf(cont)) {
      kfm.setGlobalCurrentFocusCycleRootPriv(null);
    }
  }

  final Container getTraversalRoot() {
    if (isFocusCycleRoot()) {
      return findTraversalRoot();
    }

    return super.getTraversalRoot();
  }

  /**
   * Sets the focus traversal policy that will manage keyboard traversal of
   * this Container's children, if this Container is a focus cycle root. If
   * the argument is null, this Container inherits its policy from its focus-
   * cycle-root ancestor. If the argument is non-null, this policy will be
   * inherited by all focus-cycle-root children that have no keyboard-
   * traversal policy of their own (as will, recursively, their focus-cycle-
   * root children).
   * <p>
   * If this Container is not a focus cycle root, the policy will be
   * remembered, but will not be used or inherited by this or any other
   * Containers until this Container is made a focus cycle root.
   *
   * @param policy the new focus traversal policy for this Container
   * @beaninfo bound: true
   * @see #getFocusTraversalPolicy
   * @see #setFocusCycleRoot
   * @see #isFocusCycleRoot
   * @since 1.4
   */
  public void setFocusTraversalPolicy(FocusTraversalPolicy policy) {
    FocusTraversalPolicy oldPolicy;
    synchronized (this) {
      oldPolicy = this.focusTraversalPolicy;
      this.focusTraversalPolicy = policy;
    }
    firePropertyChange("focusTraversalPolicy", oldPolicy, policy);
  }

  /**
   * Returns the focus traversal policy that will manage keyboard traversal
   * of this Container's children, or null if this Container is not a focus
   * cycle root. If no traversal policy has been explicitly set for this
   * Container, then this Container's focus-cycle-root ancestor's policy is
   * returned.
   *
   * @return this Container's focus traversal policy, or null if this Container is not a focus cycle
   * root.
   * @see #setFocusTraversalPolicy
   * @see #setFocusCycleRoot
   * @see #isFocusCycleRoot
   * @since 1.4
   */
  public FocusTraversalPolicy getFocusTraversalPolicy() {
    if (!isFocusTraversalPolicyProvider() && !isFocusCycleRoot()) {
      return null;
    }

    FocusTraversalPolicy policy = this.focusTraversalPolicy;
    if (policy != null) {
      return policy;
    }

    Container rootAncestor = getFocusCycleRootAncestor();
    if (rootAncestor != null) {
      return rootAncestor.getFocusTraversalPolicy();
    } else {
      return KeyboardFocusManager.getCurrentKeyboardFocusManager().
          getDefaultFocusTraversalPolicy();
    }
  }

  /**
   * Returns whether the focus traversal policy has been explicitly set for
   * this Container. If this method returns <code>false</code>, this
   * Container will inherit its focus traversal policy from an ancestor.
   *
   * @return <code>true</code> if the focus traversal policy has been explicitly set for this
   * Container; <code>false</code> otherwise.
   * @since 1.4
   */
  public boolean isFocusTraversalPolicySet() {
    return (focusTraversalPolicy != null);
  }

  /**
   * Sets whether this Container is the root of a focus traversal cycle. Once focus enters a
   * traversal cycle, typically it cannot leave it via focus traversal unless one of the up- or
   * down-cycle keys is pressed. Normal traversal is limited to this Container, and all of this
   * Container's descendants that are not descendants of inferior focus cycle roots. Note that a
   * FocusTraversalPolicy may bend these restrictions, however. For example,
   * ContainerOrderFocusTraversalPolicy supports implicit down-cycle traversal. <p> The alternative
   * way to specify the traversal order of this Container's children is to make this Container a <a
   * href="doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus traversal policy
   * provider</a>.
   *
   * @param focusCycleRoot indicates whether this Container is the root of a focus traversal cycle
   * @beaninfo bound: true
   * @see #isFocusCycleRoot()
   * @see #setFocusTraversalPolicy
   * @see #getFocusTraversalPolicy
   * @see ContainerOrderFocusTraversalPolicy
   * @see #setFocusTraversalPolicyProvider
   * @since 1.4
   */
  public void setFocusCycleRoot(boolean focusCycleRoot) {
    boolean oldFocusCycleRoot;
    synchronized (this) {
      oldFocusCycleRoot = this.focusCycleRoot;
      this.focusCycleRoot = focusCycleRoot;
    }
    firePropertyChange("focusCycleRoot", oldFocusCycleRoot,
        focusCycleRoot);
  }

  /**
   * Returns whether this Container is the root of a focus traversal cycle.
   * Once focus enters a traversal cycle, typically it cannot leave it via
   * focus traversal unless one of the up- or down-cycle keys is pressed.
   * Normal traversal is limited to this Container, and all of this
   * Container's descendants that are not descendants of inferior focus
   * cycle roots. Note that a FocusTraversalPolicy may bend these
   * restrictions, however. For example, ContainerOrderFocusTraversalPolicy
   * supports implicit down-cycle traversal.
   *
   * @return whether this Container is the root of a focus traversal cycle
   * @see #setFocusCycleRoot
   * @see #setFocusTraversalPolicy
   * @see #getFocusTraversalPolicy
   * @see ContainerOrderFocusTraversalPolicy
   * @since 1.4
   */
  public boolean isFocusCycleRoot() {
    return focusCycleRoot;
  }

  /**
   * Sets whether this container will be used to provide focus
   * traversal policy. Container with this property as
   * <code>true</code> will be used to acquire focus traversal policy
   * instead of closest focus cycle root ancestor.
   *
   * @param provider indicates whether this container will be used to provide focus traversal
   * policy
   * @beaninfo bound: true
   * @see #setFocusTraversalPolicy
   * @see #getFocusTraversalPolicy
   * @see #isFocusTraversalPolicyProvider
   * @since 1.5
   */
  public final void setFocusTraversalPolicyProvider(boolean provider) {
    boolean oldProvider;
    synchronized (this) {
      oldProvider = focusTraversalPolicyProvider;
      focusTraversalPolicyProvider = provider;
    }
    firePropertyChange("focusTraversalPolicyProvider", oldProvider, provider);
  }

  /**
   * Returns whether this container provides focus traversal
   * policy. If this property is set to <code>true</code> then when
   * keyboard focus manager searches container hierarchy for focus
   * traversal policy and encounters this container before any other
   * container with this property as true or focus cycle roots then
   * its focus traversal policy will be used instead of focus cycle
   * root's policy.
   *
   * @return <code>true</code> if this container provides focus traversal policy, <code>false</code>
   * otherwise
   * @beaninfo bound: true
   * @see #setFocusTraversalPolicy
   * @see #getFocusTraversalPolicy
   * @see #setFocusCycleRoot
   * @see #setFocusTraversalPolicyProvider
   * @since 1.5
   */
  public final boolean isFocusTraversalPolicyProvider() {
    return focusTraversalPolicyProvider;
  }

  /**
   * Transfers the focus down one focus traversal cycle. If this Container is
   * a focus cycle root, then the focus owner is set to this Container's
   * default Component to focus, and the current focus cycle root is set to
   * this Container. If this Container is not a focus cycle root, then no
   * focus traversal operation occurs.
   *
   * @see Component#requestFocus()
   * @see #isFocusCycleRoot
   * @see #setFocusCycleRoot
   * @since 1.4
   */
  public void transferFocusDownCycle() {
    if (isFocusCycleRoot()) {
      KeyboardFocusManager.getCurrentKeyboardFocusManager().
          setGlobalCurrentFocusCycleRootPriv(this);
      Component toFocus = getFocusTraversalPolicy().
          getDefaultComponent(this);
      if (toFocus != null) {
        toFocus.requestFocus(CausedFocusEvent.Cause.TRAVERSAL_DOWN);
      }
    }
  }

  void preProcessKeyEvent(KeyEvent e) {
    Container parent = this.parent;
    if (parent != null) {
      parent.preProcessKeyEvent(e);
    }
  }

  void postProcessKeyEvent(KeyEvent e) {
    Container parent = this.parent;
    if (parent != null) {
      parent.postProcessKeyEvent(e);
    }
  }

  boolean postsOldMouseEvents() {
    return true;
  }

  /**
   * Sets the <code>ComponentOrientation</code> property of this container
   * and all components contained within it.
   * <p>
   * This method changes layout-related information, and therefore,
   * invalidates the component hierarchy.
   *
   * @param o the new component orientation of this container and the components contained within
   * it.
   * @throws NullPointerException if <code>orientation</code> is null.
   * @see Component#setComponentOrientation
   * @see Component#getComponentOrientation
   * @see #invalidate
   * @since 1.4
   */
  public void applyComponentOrientation(ComponentOrientation o) {
    super.applyComponentOrientation(o);
    synchronized (getTreeLock()) {
      for (int i = 0; i < component.size(); i++) {
        Component comp = component.get(i);
        comp.applyComponentOrientation(o);
      }
    }
  }

  /**
   * Adds a PropertyChangeListener to the listener list. The listener is
   * registered for all bound properties of this class, including the
   * following:
   * <ul>
   * <li>this Container's font ("font")</li>
   * <li>this Container's background color ("background")</li>
   * <li>this Container's foreground color ("foreground")</li>
   * <li>this Container's focusability ("focusable")</li>
   * <li>this Container's focus traversal keys enabled state
   * ("focusTraversalKeysEnabled")</li>
   * <li>this Container's Set of FORWARD_TRAVERSAL_KEYS
   * ("forwardFocusTraversalKeys")</li>
   * <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS
   * ("backwardFocusTraversalKeys")</li>
   * <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS
   * ("upCycleFocusTraversalKeys")</li>
   * <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS
   * ("downCycleFocusTraversalKeys")</li>
   * <li>this Container's focus traversal policy ("focusTraversalPolicy")
   * </li>
   * <li>this Container's focus-cycle-root state ("focusCycleRoot")</li>
   * </ul>
   * Note that if this Container is inheriting a bound property, then no
   * event will be fired in response to a change in the inherited property.
   * <p>
   * If listener is null, no exception is thrown and no action is performed.
   *
   * @param listener the PropertyChangeListener to be added
   * @see Component#removePropertyChangeListener
   * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
   */
  public void addPropertyChangeListener(PropertyChangeListener listener) {
    super.addPropertyChangeListener(listener);
  }

  /**
   * Adds a PropertyChangeListener to the listener list for a specific
   * property. The specified property may be user-defined, or one of the
   * following defaults:
   * <ul>
   * <li>this Container's font ("font")</li>
   * <li>this Container's background color ("background")</li>
   * <li>this Container's foreground color ("foreground")</li>
   * <li>this Container's focusability ("focusable")</li>
   * <li>this Container's focus traversal keys enabled state
   * ("focusTraversalKeysEnabled")</li>
   * <li>this Container's Set of FORWARD_TRAVERSAL_KEYS
   * ("forwardFocusTraversalKeys")</li>
   * <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS
   * ("backwardFocusTraversalKeys")</li>
   * <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS
   * ("upCycleFocusTraversalKeys")</li>
   * <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS
   * ("downCycleFocusTraversalKeys")</li>
   * <li>this Container's focus traversal policy ("focusTraversalPolicy")
   * </li>
   * <li>this Container's focus-cycle-root state ("focusCycleRoot")</li>
   * <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li>
   * <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li>
   * </ul>
   * Note that if this Container is inheriting a bound property, then no
   * event will be fired in response to a change in the inherited property.
   * <p>
   * If listener is null, no exception is thrown and no action is performed.
   *
   * @param propertyName one of the property names listed above
   * @param listener the PropertyChangeListener to be added
   * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
   * @see Component#removePropertyChangeListener
   */
  public void addPropertyChangeListener(String propertyName,
      PropertyChangeListener listener) {
    super.addPropertyChangeListener(propertyName, listener);
  }

  // Serialization support. A Container is responsible for restoring the
  // parent fields of its component children.

  /**
   * Container Serial Data Version.
   */
  private int containerSerializedDataVersion = 1;

  /**
   * Serializes this <code>Container</code> to the specified
   * <code>ObjectOutputStream</code>.
   * <ul>
   * <li>Writes default serializable fields to the stream.</li>
   * <li>Writes a list of serializable ContainerListener(s) as optional
   * data. The non-serializable ContainerListner(s) are detected and
   * no attempt is made to serialize them.</li>
   * <li>Write this Container's FocusTraversalPolicy if and only if it
   * is Serializable; otherwise, <code>null</code> is written.</li>
   * </ul>
   *
   * @param s the <code>ObjectOutputStream</code> to write
   * @serialData <code>null</code> terminated sequence of 0 or more pairs; the pair consists of a
   * <code>String</code> and <code>Object</code>; the <code>String</code> indicates the type of
   * object and is one of the following: <code>containerListenerK</code> indicating an
   * <code>ContainerListener</code> object; the <code>Container</code>'s
   * <code>FocusTraversalPolicy</code>, or <code>null</code>
   * @see AWTEventMulticaster#save(java.io.ObjectOutputStream, java.lang.String,
   * java.util.EventListener)
   * @see Container#containerListenerK
   * @see #readObject(ObjectInputStream)
   */
  private void writeObject(ObjectOutputStream s) throws IOException {
    ObjectOutputStream.PutField f = s.putFields();
    f.put("ncomponents", component.size());
    f.put("component", component.toArray(EMPTY_ARRAY));
    f.put("layoutMgr", layoutMgr);
    f.put("dispatcher", dispatcher);
    f.put("maxSize", maxSize);
    f.put("focusCycleRoot", focusCycleRoot);
    f.put("containerSerializedDataVersion", containerSerializedDataVersion);
    f.put("focusTraversalPolicyProvider", focusTraversalPolicyProvider);
    s.writeFields();

    AWTEventMulticaster.save(s, containerListenerK, containerListener);
    s.writeObject(null);

    if (focusTraversalPolicy instanceof java.io.Serializable) {
      s.writeObject(focusTraversalPolicy);
    } else {
      s.writeObject(null);
    }
  }

  /**
   * Deserializes this <code>Container</code> from the specified
   * <code>ObjectInputStream</code>.
   * <ul>
   * <li>Reads default serializable fields from the stream.</li>
   * <li>Reads a list of serializable ContainerListener(s) as optional
   * data. If the list is null, no Listeners are installed.</li>
   * <li>Reads this Container's FocusTraversalPolicy, which may be null,
   * as optional data.</li>
   * </ul>
   *
   * @param s the <code>ObjectInputStream</code> to read
   * @serial
   * @see #addContainerListener
   * @see #writeObject(ObjectOutputStream)
   */
  private void readObject(ObjectInputStream s)
      throws ClassNotFoundException, IOException {
    ObjectInputStream.GetField f = s.readFields();
    Component[] tmpComponent = (Component[]) f.get("component", EMPTY_ARRAY);
    int ncomponents = (Integer) f.get("ncomponents", 0);
    component = new java.util.ArrayList<Component>(ncomponents);
    for (int i = 0; i < ncomponents; ++i) {
      component.add(tmpComponent[i]);
    }
    layoutMgr = (LayoutManager) f.get("layoutMgr", null);
    dispatcher = (LightweightDispatcher) f.get("dispatcher", null);
    // Old stream. Doesn't contain maxSize among Component's fields.
    if (maxSize == null) {
      maxSize = (Dimension) f.get("maxSize", null);
    }
    focusCycleRoot = f.get("focusCycleRoot", false);
    containerSerializedDataVersion = f.get("containerSerializedDataVersion", 1);
    focusTraversalPolicyProvider = f.get("focusTraversalPolicyProvider", false);
    java.util.List<Component> component = this.component;
    for (Component comp : component) {
      comp.parent = this;
      adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
          comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
      adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
          comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
      adjustDescendants(comp.countHierarchyMembers());
    }

    Object keyOrNull;
    while (null != (keyOrNull = s.readObject())) {
      String key = ((String) keyOrNull).intern();

      if (containerListenerK == key) {
        addContainerListener((ContainerListener) (s.readObject()));
      } else {
        // skip value for unrecognized key
        s.readObject();
      }
    }

    try {
      Object policy = s.readObject();
      if (policy instanceof FocusTraversalPolicy) {
        focusTraversalPolicy = (FocusTraversalPolicy) policy;
      }
    } catch (java.io.OptionalDataException e) {
      // JDK 1.1/1.2/1.3 instances will not have this optional data.
      // e.eof will be true to indicate that there is no more data
      // available for this object. If e.eof is not true, throw the
      // exception as it might have been caused by reasons unrelated to
      // focusTraversalPolicy.

      if (!e.eof) {
        throw e;
      }
    }
  }

    /*
     * --- Accessibility Support ---
     */

  /**
   * Inner class of Container used to provide default support for
   * accessibility.  This class is not meant to be used directly by
   * application developers, but is instead meant only to be
   * subclassed by container developers.
   * <p>
   * The class used to obtain the accessible role for this object,
   * as well as implementing many of the methods in the
   * AccessibleContainer interface.
   *
   * @since 1.3
   */
  protected class AccessibleAWTContainer extends AccessibleAWTComponent {

    /**
     * JDK1.3 serialVersionUID
     */
    private static final long serialVersionUID = 5081320404842566097L;

    /**
     * Returns the number of accessible children in the object.  If all
     * of the children of this object implement <code>Accessible</code>,
     * then this method should return the number of children of this object.
     *
     * @return the number of accessible children in the object
     */
    public int getAccessibleChildrenCount() {
      return Container.this.getAccessibleChildrenCount();
    }

    /**
     * Returns the nth <code>Accessible</code> child of the object.
     *
     * @param i zero-based index of child
     * @return the nth <code>Accessible</code> child of the object
     */
    public Accessible getAccessibleChild(int i) {
      return Container.this.getAccessibleChild(i);
    }

    /**
     * Returns the <code>Accessible</code> child, if one exists,
     * contained at the local coordinate <code>Point</code>.
     *
     * @param p the point defining the top-left corner of the <code>Accessible</code>, given in the
     * coordinate space of the object's parent
     * @return the <code>Accessible</code>, if it exists, at the specified location; else
     * <code>null</code>
     */
    public Accessible getAccessibleAt(Point p) {
      return Container.this.getAccessibleAt(p);
    }

    /**
     * Number of PropertyChangeListener objects registered. It's used
     * to add/remove ContainerListener to track target Container's state.
     */
    private volatile transient int propertyListenersCount = 0;

    protected ContainerListener accessibleContainerHandler = null;

    /**
     * Fire <code>PropertyChange</code> listener, if one is registered,
     * when children are added or removed.
     *
     * @since 1.3
     */
    protected class AccessibleContainerHandler
        implements ContainerListener {

      public void componentAdded(ContainerEvent e) {
        Component c = e.getChild();
        if (c != null && c instanceof Accessible) {
          AccessibleAWTContainer.this.firePropertyChange(
              AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
              null, ((Accessible) c).getAccessibleContext());
        }
      }

      public void componentRemoved(ContainerEvent e) {
        Component c = e.getChild();
        if (c != null && c instanceof Accessible) {
          AccessibleAWTContainer.this.firePropertyChange(
              AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
              ((Accessible) c).getAccessibleContext(), null);
        }
      }
    }

    /**
     * Adds a PropertyChangeListener to the listener list.
     *
     * @param listener the PropertyChangeListener to be added
     */
    public void addPropertyChangeListener(PropertyChangeListener listener) {
      if (accessibleContainerHandler == null) {
        accessibleContainerHandler = new AccessibleContainerHandler();
      }
      if (propertyListenersCount++ == 0) {
        Container.this.addContainerListener(accessibleContainerHandler);
      }
      super.addPropertyChangeListener(listener);
    }

    /**
     * Remove a PropertyChangeListener from the listener list.
     * This removes a PropertyChangeListener that was registered
     * for all properties.
     *
     * @param listener the PropertyChangeListener to be removed
     */
    public void removePropertyChangeListener(PropertyChangeListener listener) {
      if (--propertyListenersCount == 0) {
        Container.this.removeContainerListener(accessibleContainerHandler);
      }
      super.removePropertyChangeListener(listener);
    }

  } // inner class AccessibleAWTContainer

  /**
   * Returns the <code>Accessible</code> child contained at the local
   * coordinate <code>Point</code>, if one exists.  Otherwise
   * returns <code>null</code>.
   *
   * @param p the point defining the top-left corner of the <code>Accessible</code>, given in the
   * coordinate space of the object's parent
   * @return the <code>Accessible</code> at the specified location, if it exists; otherwise
   * <code>null</code>
   */
  Accessible getAccessibleAt(Point p) {
    synchronized (getTreeLock()) {
      if (this instanceof Accessible) {
        Accessible a = (Accessible) this;
        AccessibleContext ac = a.getAccessibleContext();
        if (ac != null) {
          AccessibleComponent acmp;
          Point location;
          int nchildren = ac.getAccessibleChildrenCount();
          for (int i = 0; i < nchildren; i++) {
            a = ac.getAccessibleChild(i);
            if ((a != null)) {
              ac = a.getAccessibleContext();
              if (ac != null) {
                acmp = ac.getAccessibleComponent();
                if ((acmp != null) && (acmp.isShowing())) {
                  location = acmp.getLocation();
                  Point np = new Point(p.x - location.x,
                      p.y - location.y);
                  if (acmp.contains(np)) {
                    return a;
                  }
                }
              }
            }
          }
        }
        return (Accessible) this;
      } else {
        Component ret = this;
        if (!this.contains(p.x, p.y)) {
          ret = null;
        } else {
          int ncomponents = this.getComponentCount();
          for (int i = 0; i < ncomponents; i++) {
            Component comp = this.getComponent(i);
            if ((comp != null) && comp.isShowing()) {
              Point location = comp.getLocation();
              if (comp.contains(p.x - location.x, p.y - location.y)) {
                ret = comp;
              }
            }
          }
        }
        if (ret instanceof Accessible) {
          return (Accessible) ret;
        }
      }
      return null;
    }
  }

  /**
   * Returns the number of accessible children in the object.  If all
   * of the children of this object implement <code>Accessible</code>,
   * then this method should return the number of children of this object.
   *
   * @return the number of accessible children in the object
   */
  int getAccessibleChildrenCount() {
    synchronized (getTreeLock()) {
      int count = 0;
      Component[] children = this.getComponents();
      for (int i = 0; i < children.length; i++) {
        if (children[i] instanceof Accessible) {
          count++;
        }
      }
      return count;
    }
  }

  /**
   * Returns the nth <code>Accessible</code> child of the object.
   *
   * @param i zero-based index of child
   * @return the nth <code>Accessible</code> child of the object
   */
  Accessible getAccessibleChild(int i) {
    synchronized (getTreeLock()) {
      Component[] children = this.getComponents();
      int count = 0;
      for (int j = 0; j < children.length; j++) {
        if (children[j] instanceof Accessible) {
          if (count == i) {
            return (Accessible) children[j];
          } else {
            count++;
          }
        }
      }
      return null;
    }
  }

  // ************************** MIXING CODE *******************************

  final void increaseComponentCount(Component c) {
    synchronized (getTreeLock()) {
      if (!c.isDisplayable()) {
        throw new IllegalStateException(
            "Peer does not exist while invoking the increaseComponentCount() method"
        );
      }

      int addHW = 0;
      int addLW = 0;

      if (c instanceof Container) {
        addLW = ((Container) c).numOfLWComponents;
        addHW = ((Container) c).numOfHWComponents;
      }
      if (c.isLightweight()) {
        addLW++;
      } else {
        addHW++;
      }

      for (Container cont = this; cont != null; cont = cont.getContainer()) {
        cont.numOfLWComponents += addLW;
        cont.numOfHWComponents += addHW;
      }
    }
  }

  final void decreaseComponentCount(Component c) {
    synchronized (getTreeLock()) {
      if (!c.isDisplayable()) {
        throw new IllegalStateException(
            "Peer does not exist while invoking the decreaseComponentCount() method"
        );
      }

      int subHW = 0;
      int subLW = 0;

      if (c instanceof Container) {
        subLW = ((Container) c).numOfLWComponents;
        subHW = ((Container) c).numOfHWComponents;
      }
      if (c.isLightweight()) {
        subLW++;
      } else {
        subHW++;
      }

      for (Container cont = this; cont != null; cont = cont.getContainer()) {
        cont.numOfLWComponents -= subLW;
        cont.numOfHWComponents -= subHW;
      }
    }
  }

  private int getTopmostComponentIndex() {
    checkTreeLock();
    if (getComponentCount() > 0) {
      return 0;
    }
    return -1;
  }

  private int getBottommostComponentIndex() {
    checkTreeLock();
    if (getComponentCount() > 0) {
      return getComponentCount() - 1;
    }
    return -1;
  }

  /*
     * This method is overriden to handle opaque children in non-opaque
     * containers.
     */
  @Override
  final Region getOpaqueShape() {
    checkTreeLock();
    if (isLightweight() && isNonOpaqueForMixing()
        && hasLightweightDescendants()) {
      Region s = Region.EMPTY_REGION;
      for (int index = 0; index < getComponentCount(); index++) {
        Component c = getComponent(index);
        if (c.isLightweight() && c.isShowing()) {
          s = s.getUnion(c.getOpaqueShape());
        }
      }
      return s.getIntersection(getNormalShape());
    }
    return super.getOpaqueShape();
  }

  final void recursiveSubtractAndApplyShape(Region shape) {
    recursiveSubtractAndApplyShape(shape, getTopmostComponentIndex(),
        getBottommostComponentIndex());
  }

  final void recursiveSubtractAndApplyShape(Region shape, int fromZorder) {
    recursiveSubtractAndApplyShape(shape, fromZorder, getBottommostComponentIndex());
  }

  final void recursiveSubtractAndApplyShape(Region shape, int fromZorder, int toZorder) {
    checkTreeLock();
    if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
      mixingLog.fine("this = " + this +
          "; shape=" + shape + "; fromZ=" + fromZorder + "; toZ=" + toZorder);
    }
    if (fromZorder == -1) {
      return;
    }
    if (shape.isEmpty()) {
      return;
    }
    // An invalid container with not-null layout should be ignored
    // by the mixing code, the container will be validated later
    // and the mixing code will be executed later.
    if (getLayout() != null && !isValid()) {
      return;
    }
    for (int index = fromZorder; index <= toZorder; index++) {
      Component comp = getComponent(index);
      if (!comp.isLightweight()) {
        comp.subtractAndApplyShape(shape);
      } else if (comp instanceof Container &&
          ((Container) comp).hasHeavyweightDescendants() && comp.isShowing()) {
        ((Container) comp).recursiveSubtractAndApplyShape(shape);
      }
    }
  }

  final void recursiveApplyCurrentShape() {
    recursiveApplyCurrentShape(getTopmostComponentIndex(), getBottommostComponentIndex());
  }

  final void recursiveApplyCurrentShape(int fromZorder) {
    recursiveApplyCurrentShape(fromZorder, getBottommostComponentIndex());
  }

  final void recursiveApplyCurrentShape(int fromZorder, int toZorder) {
    checkTreeLock();
    if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
      mixingLog.fine("this = " + this +
          "; fromZ=" + fromZorder + "; toZ=" + toZorder);
    }
    if (fromZorder == -1) {
      return;
    }
    // An invalid container with not-null layout should be ignored
    // by the mixing code, the container will be validated later
    // and the mixing code will be executed later.
    if (getLayout() != null && !isValid()) {
      return;
    }
    for (int index = fromZorder; index <= toZorder; index++) {
      Component comp = getComponent(index);
      if (!comp.isLightweight()) {
        comp.applyCurrentShape();
      }
      if (comp instanceof Container &&
          ((Container) comp).hasHeavyweightDescendants()) {
        ((Container) comp).recursiveApplyCurrentShape();
      }
    }
  }

  private void recursiveShowHeavyweightChildren() {
    if (!hasHeavyweightDescendants() || !isVisible()) {
      return;
    }
    for (int index = 0; index < getComponentCount(); index++) {
      Component comp = getComponent(index);
      if (comp.isLightweight()) {
        if (comp instanceof Container) {
          ((Container) comp).recursiveShowHeavyweightChildren();
        }
      } else {
        if (comp.isVisible()) {
          ComponentPeer peer = comp.getPeer();
          if (peer != null) {
            peer.setVisible(true);
          }
        }
      }
    }
  }

  private void recursiveHideHeavyweightChildren() {
    if (!hasHeavyweightDescendants()) {
      return;
    }
    for (int index = 0; index < getComponentCount(); index++) {
      Component comp = getComponent(index);
      if (comp.isLightweight()) {
        if (comp instanceof Container) {
          ((Container) comp).recursiveHideHeavyweightChildren();
        }
      } else {
        if (comp.isVisible()) {
          ComponentPeer peer = comp.getPeer();
          if (peer != null) {
            peer.setVisible(false);
          }
        }
      }
    }
  }

  private void recursiveRelocateHeavyweightChildren(Point origin) {
    for (int index = 0; index < getComponentCount(); index++) {
      Component comp = getComponent(index);
      if (comp.isLightweight()) {
        if (comp instanceof Container &&
            ((Container) comp).hasHeavyweightDescendants()) {
          final Point newOrigin = new Point(origin);
          newOrigin.translate(comp.getX(), comp.getY());
          ((Container) comp).recursiveRelocateHeavyweightChildren(newOrigin);
        }
      } else {
        ComponentPeer peer = comp.getPeer();
        if (peer != null) {
          peer.setBounds(origin.x + comp.getX(), origin.y + comp.getY(),
              comp.getWidth(), comp.getHeight(),
              ComponentPeer.SET_LOCATION);
        }
      }
    }
  }

  /**
   * Checks if the container and its direct lightweight containers are
   * visible.
   *
   * Consider the heavyweight container hides or shows the HW descendants
   * automatically. Therefore we care of LW containers' visibility only.
   *
   * This method MUST be invoked under the TreeLock.
   */
  final boolean isRecursivelyVisibleUpToHeavyweightContainer() {
    if (!isLightweight()) {
      return true;
    }

    for (Container cont = this;
        cont != null && cont.isLightweight();
        cont = cont.getContainer()) {
      if (!cont.isVisible()) {
        return false;
      }
    }
    return true;
  }

  @Override
  void mixOnShowing() {
    synchronized (getTreeLock()) {
      if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
        mixingLog.fine("this = " + this);
      }

      boolean isLightweight = isLightweight();

      if (isLightweight && isRecursivelyVisibleUpToHeavyweightContainer()) {
        recursiveShowHeavyweightChildren();
      }

      if (!isMixingNeeded()) {
        return;
      }

      if (!isLightweight || (isLightweight && hasHeavyweightDescendants())) {
        recursiveApplyCurrentShape();
      }

      super.mixOnShowing();
    }
  }

  @Override
  void mixOnHiding(boolean isLightweight) {
    synchronized (getTreeLock()) {
      if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
        mixingLog.fine("this = " + this +
            "; isLightweight=" + isLightweight);
      }
      if (isLightweight) {
        recursiveHideHeavyweightChildren();
      }
      super.mixOnHiding(isLightweight);
    }
  }

  @Override
  void mixOnReshaping() {
    synchronized (getTreeLock()) {
      if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
        mixingLog.fine("this = " + this);
      }

      boolean isMixingNeeded = isMixingNeeded();

      if (isLightweight() && hasHeavyweightDescendants()) {
        final Point origin = new Point(getX(), getY());
        for (Container cont = getContainer();
            cont != null && cont.isLightweight();
            cont = cont.getContainer()) {
          origin.translate(cont.getX(), cont.getY());
        }

        recursiveRelocateHeavyweightChildren(origin);

        if (!isMixingNeeded) {
          return;
        }

        recursiveApplyCurrentShape();
      }

      if (!isMixingNeeded) {
        return;
      }

      super.mixOnReshaping();
    }
  }

  @Override
  void mixOnZOrderChanging(int oldZorder, int newZorder) {
    synchronized (getTreeLock()) {
      if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
        mixingLog.fine("this = " + this +
            "; oldZ=" + oldZorder + "; newZ=" + newZorder);
      }

      if (!isMixingNeeded()) {
        return;
      }

      boolean becameHigher = newZorder < oldZorder;

      if (becameHigher && isLightweight() && hasHeavyweightDescendants()) {
        recursiveApplyCurrentShape();
      }
      super.mixOnZOrderChanging(oldZorder, newZorder);
    }
  }

  @Override
  void mixOnValidating() {
    synchronized (getTreeLock()) {
      if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) {
        mixingLog.fine("this = " + this);
      }

      if (!isMixingNeeded()) {
        return;
      }

      if (hasHeavyweightDescendants()) {
        recursiveApplyCurrentShape();
      }

      if (isLightweight() && isNonOpaqueForMixing()) {
        subtractAndApplyShapeBelowMe();
      }

      super.mixOnValidating();
    }
  }

  // ****************** END OF MIXING CODE ********************************
}


/**
 * Class to manage the dispatching of MouseEvents to the lightweight descendants
 * and SunDropTargetEvents to both lightweight and heavyweight descendants
 * contained by a native container.
 *
 * NOTE: the class name is not appropriate anymore, but we cannot change it
 * because we must keep serialization compatibility.
 *
 * @author Timothy Prinzing
 */
class LightweightDispatcher implements java.io.Serializable, AWTEventListener {

  /*
     * JDK 1.1 serialVersionUID
     */
  private static final long serialVersionUID = 5184291520170872969L;
  /*
     * Our own mouse event for when we're dragged over from another hw
     * container
     */
  private static final int LWD_MOUSE_DRAGGED_OVER = 1500;

  private static final PlatformLogger eventLog = PlatformLogger
      .getLogger("java.awt.event.LightweightDispatcher");

  private static final int BUTTONS_DOWN_MASK;

  static {
    int[] buttonsDownMask = AWTAccessor.getInputEventAccessor().
        getButtonDownMasks();
    int mask = 0;
    for (int buttonDownMask : buttonsDownMask) {
      mask |= buttonDownMask;
    }
    BUTTONS_DOWN_MASK = mask;
  }

  LightweightDispatcher(Container nativeContainer) {
    this.nativeContainer = nativeContainer;
    mouseEventTarget = new WeakReference<>(null);
    targetLastEntered = new WeakReference<>(null);
    targetLastEnteredDT = new WeakReference<>(null);
    eventMask = 0;
  }

  /*
     * Clean up any resources allocated when dispatcher was created;
     * should be called from Container.removeNotify
     */
  void dispose() {
    //System.out.println("Disposing lw dispatcher");
    stopListeningForOtherDrags();
    mouseEventTarget.clear();
    targetLastEntered.clear();
    targetLastEnteredDT.clear();
  }

  /**
   * Enables events to subcomponents.
   */
  void enableEvents(long events) {
    eventMask |= events;
  }

  /**
   * Dispatches an event to a sub-component if necessary, and
   * returns whether or not the event was forwarded to a
   * sub-component.
   *
   * @param e the event
   */
  boolean dispatchEvent(AWTEvent e) {
    boolean ret = false;

        /*
         * Fix for BugTraq Id 4389284.
         * Dispatch SunDropTargetEvents regardless of eventMask value.
         * Do not update cursor on dispatching SunDropTargetEvents.
         */
    if (e instanceof SunDropTargetEvent) {

      SunDropTargetEvent sdde = (SunDropTargetEvent) e;
      ret = processDropTargetEvent(sdde);

    } else {
      if (e instanceof MouseEvent && (eventMask & MOUSE_MASK) != 0) {
        MouseEvent me = (MouseEvent) e;
        ret = processMouseEvent(me);
      }

      if (e.getID() == MouseEvent.MOUSE_MOVED) {
        nativeContainer.updateCursorImmediately();
      }
    }

    return ret;
  }

  /* This method effectively returns whether or not a mouse button was down
     * just BEFORE the event happened.  A better method name might be
     * wasAMouseButtonDownBeforeThisEvent().
     */
  private boolean isMouseGrab(MouseEvent e) {
    int modifiers = e.getModifiersEx();

    if (e.getID() == MouseEvent.MOUSE_PRESSED
        || e.getID() == MouseEvent.MOUSE_RELEASED) {
      modifiers ^= InputEvent.getMaskForButton(e.getButton());
    }
        /* modifiers now as just before event */
    return ((modifiers & BUTTONS_DOWN_MASK) != 0);
  }

  /**
   * This method attempts to distribute a mouse event to a lightweight
   * component.  It tries to avoid doing any unnecessary probes down
   * into the component tree to minimize the overhead of determining
   * where to route the event, since mouse movement events tend to
   * come in large and frequent amounts.
   */
  private boolean processMouseEvent(MouseEvent e) {
    int id = e.getID();
    Component mouseOver =   // sensitive to mouse events
        nativeContainer.getMouseEventTarget(e.getX(), e.getY(),
            Container.INCLUDE_SELF);

    trackMouseEnterExit(mouseOver, e);

    Component met = mouseEventTarget.get();
    // 4508327 : MOUSE_CLICKED should only go to the recipient of
    // the accompanying MOUSE_PRESSED, so don't reset mouseEventTarget on a
    // MOUSE_CLICKED.
    if (!isMouseGrab(e) && id != MouseEvent.MOUSE_CLICKED) {
      met = (mouseOver != nativeContainer) ? mouseOver : null;
      mouseEventTarget = new WeakReference<>(met);
    }

    if (met != null) {
      switch (id) {
        case MouseEvent.MOUSE_ENTERED:
        case MouseEvent.MOUSE_EXITED:
          break;
        case MouseEvent.MOUSE_PRESSED:
          retargetMouseEvent(met, id, e);
          break;
        case MouseEvent.MOUSE_RELEASED:
          retargetMouseEvent(met, id, e);
          break;
        case MouseEvent.MOUSE_CLICKED:
          // 4508327: MOUSE_CLICKED should never be dispatched to a Component
          // other than that which received the MOUSE_PRESSED event.  If the
          // mouse is now over a different Component, don't dispatch the event.
          // The previous fix for a similar problem was associated with bug
          // 4155217.
          if (mouseOver == met) {
            retargetMouseEvent(mouseOver, id, e);
          }
          break;
        case MouseEvent.MOUSE_MOVED:
          retargetMouseEvent(met, id, e);
          break;
        case MouseEvent.MOUSE_DRAGGED:
          if (isMouseGrab(e)) {
            retargetMouseEvent(met, id, e);
          }
          break;
        case MouseEvent.MOUSE_WHEEL:
          // This may send it somewhere that doesn't have MouseWheelEvents
          // enabled.  In this case, Component.dispatchEventImpl() will
          // retarget the event to a parent that DOES have the events enabled.
          if (eventLog.isLoggable(PlatformLogger.Level.FINEST) && (mouseOver != null)) {
            eventLog.finest("retargeting mouse wheel to " +
                mouseOver.getName() + ", " +
                mouseOver.getClass());
          }
          retargetMouseEvent(mouseOver, id, e);
          break;
      }
      //Consuming of wheel events is implemented in "retargetMouseEvent".
      if (id != MouseEvent.MOUSE_WHEEL) {
        e.consume();
      }
    }
    return e.isConsumed();
  }

  private boolean processDropTargetEvent(SunDropTargetEvent e) {
    int id = e.getID();
    int x = e.getX();
    int y = e.getY();

        /*
         * Fix for BugTraq ID 4395290.
         * It is possible that SunDropTargetEvent's Point is outside of the
         * native container bounds. In this case we truncate coordinates.
         */
    if (!nativeContainer.contains(x, y)) {
      final Dimension d = nativeContainer.getSize();
      if (d.width <= x) {
        x = d.width - 1;
      } else if (x < 0) {
        x = 0;
      }
      if (d.height <= y) {
        y = d.height - 1;
      } else if (y < 0) {
        y = 0;
      }
    }
    Component mouseOver =   // not necessarily sensitive to mouse events
        nativeContainer.getDropTargetEventTarget(x, y,
            Container.INCLUDE_SELF);
    trackMouseEnterExit(mouseOver, e);

    if (mouseOver != nativeContainer && mouseOver != null) {
      switch (id) {
        case SunDropTargetEvent.MOUSE_ENTERED:
        case SunDropTargetEvent.MOUSE_EXITED:
          break;
        default:
          retargetMouseEvent(mouseOver, id, e);
          e.consume();
          break;
      }
    }
    return e.isConsumed();
  }

  /*
     * Generates dnd enter/exit events as mouse moves over lw components
     * @param targetOver       Target mouse is over (including native container)
     * @param e                SunDropTarget mouse event in native container
     */
  private void trackDropTargetEnterExit(Component targetOver, MouseEvent e) {
    int id = e.getID();
    if (id == MouseEvent.MOUSE_ENTERED && isMouseDTInNativeContainer) {
      // This can happen if a lightweight component which initiated the
      // drag has an associated drop target. MOUSE_ENTERED comes when the
      // mouse is in the native container already. To propagate this event
      // properly we should null out targetLastEntered.
      targetLastEnteredDT.clear();
    } else if (id == MouseEvent.MOUSE_ENTERED) {
      isMouseDTInNativeContainer = true;
    } else if (id == MouseEvent.MOUSE_EXITED) {
      isMouseDTInNativeContainer = false;
    }
    Component tle = retargetMouseEnterExit(targetOver, e,
        targetLastEnteredDT.get(),
        isMouseDTInNativeContainer);
    targetLastEnteredDT = new WeakReference<>(tle);
  }

  /*
     * Generates enter/exit events as mouse moves over lw components
     * @param targetOver        Target mouse is over (including native container)
     * @param e                 Mouse event in native container
     */
  private void trackMouseEnterExit(Component targetOver, MouseEvent e) {
    if (e instanceof SunDropTargetEvent) {
      trackDropTargetEnterExit(targetOver, e);
      return;
    }
    int id = e.getID();

    if (id != MouseEvent.MOUSE_EXITED &&
        id != MouseEvent.MOUSE_DRAGGED &&
        id != LWD_MOUSE_DRAGGED_OVER &&
        !isMouseInNativeContainer) {
      // any event but an exit or drag means we're in the native container
      isMouseInNativeContainer = true;
      startListeningForOtherDrags();
    } else if (id == MouseEvent.MOUSE_EXITED) {
      isMouseInNativeContainer = false;
      stopListeningForOtherDrags();
    }
    Component tle = retargetMouseEnterExit(targetOver, e,
        targetLastEntered.get(),
        isMouseInNativeContainer);
    targetLastEntered = new WeakReference<>(tle);
  }

  private Component retargetMouseEnterExit(Component targetOver, MouseEvent e,
      Component lastEntered,
      boolean inNativeContainer) {
    int id = e.getID();
    Component targetEnter = inNativeContainer ? targetOver : null;

    if (lastEntered != targetEnter) {
      if (lastEntered != null) {
        retargetMouseEvent(lastEntered, MouseEvent.MOUSE_EXITED, e);
      }
      if (id == MouseEvent.MOUSE_EXITED) {
        // consume native exit event if we generate one
        e.consume();
      }

      if (targetEnter != null) {
        retargetMouseEvent(targetEnter, MouseEvent.MOUSE_ENTERED, e);
      }
      if (id == MouseEvent.MOUSE_ENTERED) {
        // consume native enter event if we generate one
        e.consume();
      }
    }
    return targetEnter;
  }

  /*
     * Listens to global mouse drag events so even drags originating
     * from other heavyweight containers will generate enter/exit
     * events in this container
     */
  private void startListeningForOtherDrags() {
    //System.out.println("Adding AWTEventListener");
    java.security.AccessController.doPrivileged(
        new java.security.PrivilegedAction<Object>() {
          public Object run() {
            nativeContainer.getToolkit().addAWTEventListener(
                LightweightDispatcher.this,
                AWTEvent.MOUSE_EVENT_MASK |
                    AWTEvent.MOUSE_MOTION_EVENT_MASK);
            return null;
          }
        }
    );
  }

  private void stopListeningForOtherDrags() {
    //System.out.println("Removing AWTEventListener");
    java.security.AccessController.doPrivileged(
        new java.security.PrivilegedAction<Object>() {
          public Object run() {
            nativeContainer.getToolkit().removeAWTEventListener(LightweightDispatcher.this);
            return null;
          }
        }
    );
  }

  /*
     * (Implementation of AWTEventListener)
     * Listen for drag events posted in other hw components so we can
     * track enter/exit regardless of where a drag originated
     */
  public void eventDispatched(AWTEvent e) {
    boolean isForeignDrag = (e instanceof MouseEvent) &&
        !(e instanceof SunDropTargetEvent) &&
        (e.id == MouseEvent.MOUSE_DRAGGED) &&
        (e.getSource() != nativeContainer);

    if (!isForeignDrag) {
      // only interested in drags from other hw components
      return;
    }

    MouseEvent srcEvent = (MouseEvent) e;
    MouseEvent me;

    synchronized (nativeContainer.getTreeLock()) {
      Component srcComponent = srcEvent.getComponent();

      // component may have disappeared since drag event posted
      // (i.e. Swing hierarchical menus)
      if (!srcComponent.isShowing()) {
        return;
      }

      // see 5083555
      // check if srcComponent is in any modal blocked window
      Component c = nativeContainer;
      while ((c != null) && !(c instanceof Window)) {
        c = c.getParent_NoClientCode();
      }
      if ((c == null) || ((Window) c).isModalBlocked()) {
        return;
      }

      //
      // create an internal 'dragged-over' event indicating
      // we are being dragged over from another hw component
      //
      me = new MouseEvent(nativeContainer,
          LWD_MOUSE_DRAGGED_OVER,
          srcEvent.getWhen(),
          srcEvent.getModifiersEx() | srcEvent.getModifiers(),
          srcEvent.getX(),
          srcEvent.getY(),
          srcEvent.getXOnScreen(),
          srcEvent.getYOnScreen(),
          srcEvent.getClickCount(),
          srcEvent.isPopupTrigger(),
          srcEvent.getButton());
      ((AWTEvent) srcEvent).copyPrivateDataInto(me);
      // translate coordinates to this native container
      final Point ptSrcOrigin = srcComponent.getLocationOnScreen();

      if (AppContext.getAppContext() != nativeContainer.appContext) {
        final MouseEvent mouseEvent = me;
        Runnable r = new Runnable() {
          public void run() {
            if (!nativeContainer.isShowing()) {
              return;
            }

            Point ptDstOrigin = nativeContainer.getLocationOnScreen();
            mouseEvent.translatePoint(ptSrcOrigin.x - ptDstOrigin.x,
                ptSrcOrigin.y - ptDstOrigin.y);
            Component targetOver =
                nativeContainer.getMouseEventTarget(mouseEvent.getX(),
                    mouseEvent.getY(),
                    Container.INCLUDE_SELF);
            trackMouseEnterExit(targetOver, mouseEvent);
          }
        };
        SunToolkit.executeOnEventHandlerThread(nativeContainer, r);
        return;
      } else {
        if (!nativeContainer.isShowing()) {
          return;
        }

        Point ptDstOrigin = nativeContainer.getLocationOnScreen();
        me.translatePoint(ptSrcOrigin.x - ptDstOrigin.x, ptSrcOrigin.y - ptDstOrigin.y);
      }
    }
    //System.out.println("Track event: " + me);
    // feed the 'dragged-over' event directly to the enter/exit
    // code (not a real event so don't pass it to dispatchEvent)
    Component targetOver =
        nativeContainer.getMouseEventTarget(me.getX(), me.getY(),
            Container.INCLUDE_SELF);
    trackMouseEnterExit(targetOver, me);
  }

  /**
   * Sends a mouse event to the current mouse event recipient using
   * the given event (sent to the windowed host) as a srcEvent.  If
   * the mouse event target is still in the component tree, the
   * coordinates of the event are translated to those of the target.
   * If the target has been removed, we don't bother to send the
   * message.
   */
  void retargetMouseEvent(Component target, int id, MouseEvent e) {
    if (target == null) {
      return; // mouse is over another hw component or target is disabled
    }

    int x = e.getX(), y = e.getY();
    Component component;

    for (component = target;
        component != null && component != nativeContainer;
        component = component.getParent()) {
      x -= component.x;
      y -= component.y;
    }
    MouseEvent retargeted;
    if (component != null) {
      if (e instanceof SunDropTargetEvent) {
        retargeted = new SunDropTargetEvent(target,
            id,
            x,
            y,
            ((SunDropTargetEvent) e).getDispatcher());
      } else if (id == MouseEvent.MOUSE_WHEEL) {
        retargeted = new MouseWheelEvent(target,
            id,
            e.getWhen(),
            e.getModifiersEx() | e.getModifiers(),
            x,
            y,
            e.getXOnScreen(),
            e.getYOnScreen(),
            e.getClickCount(),
            e.isPopupTrigger(),
            ((MouseWheelEvent) e).getScrollType(),
            ((MouseWheelEvent) e).getScrollAmount(),
            ((MouseWheelEvent) e).getWheelRotation(),
            ((MouseWheelEvent) e).getPreciseWheelRotation());
      } else {
        retargeted = new MouseEvent(target,
            id,
            e.getWhen(),
            e.getModifiersEx() | e.getModifiers(),
            x,
            y,
            e.getXOnScreen(),
            e.getYOnScreen(),
            e.getClickCount(),
            e.isPopupTrigger(),
            e.getButton());
      }

      ((AWTEvent) e).copyPrivateDataInto(retargeted);

      if (target == nativeContainer) {
        // avoid recursively calling LightweightDispatcher...
        ((Container) target).dispatchEventToSelf(retargeted);
      } else {
        assert AppContext.getAppContext() == target.appContext;

        if (nativeContainer.modalComp != null) {
          if (((Container) nativeContainer.modalComp).isAncestorOf(target)) {
            target.dispatchEvent(retargeted);
          } else {
            e.consume();
          }
        } else {
          target.dispatchEvent(retargeted);
        }
      }
      if (id == MouseEvent.MOUSE_WHEEL && retargeted.isConsumed()) {
        //An exception for wheel bubbling to the native system.
        //In "processMouseEvent" total event consuming for wheel events is skipped.
        //Protection from bubbling of Java-accepted wheel events.
        e.consume();
      }
    }
  }

  // --- member variables -------------------------------

  /**
   * The windowed container that might be hosting events for
   * subcomponents.
   */
  private Container nativeContainer;

  /**
   * This variable is not used, but kept for serialization compatibility
   */
  private Component focus;

  /**
   * The current subcomponent being hosted by this windowed
   * component that has events being forwarded to it.  If this
   * is null, there are currently no events being forwarded to
   * a subcomponent.
   */
  private transient WeakReference<Component> mouseEventTarget;

  /**
   * The last component entered by the {@code MouseEvent}.
   */
  private transient WeakReference<Component> targetLastEntered;

  /**
   * The last component entered by the {@code SunDropTargetEvent}.
   */
  private transient WeakReference<Component> targetLastEnteredDT;

  /**
   * Is the mouse over the native container.
   */
  private transient boolean isMouseInNativeContainer = false;

  /**
   * Is DnD over the native container.
   */
  private transient boolean isMouseDTInNativeContainer = false;

  /**
   * This variable is not used, but kept for serialization compatibility
   */
  private Cursor nativeCursor;

  /**
   * The event mask for contained lightweight components.  Lightweight
   * components need a windowed container to host window-related
   * events.  This separate mask indicates events that have been
   * requested by contained lightweight components without effecting
   * the mask of the windowed component itself.
   */
  private long eventMask;

  /**
   * The kind of events routed to lightweight components from windowed
   * hosts.
   */
  private static final long PROXY_EVENT_MASK =
      AWTEvent.FOCUS_EVENT_MASK |
          AWTEvent.KEY_EVENT_MASK |
          AWTEvent.MOUSE_EVENT_MASK |
          AWTEvent.MOUSE_MOTION_EVENT_MASK |
          AWTEvent.MOUSE_WHEEL_EVENT_MASK;

  private static final long MOUSE_MASK =
      AWTEvent.MOUSE_EVENT_MASK |
          AWTEvent.MOUSE_MOTION_EVENT_MASK |
          AWTEvent.MOUSE_WHEEL_EVENT_MASK;
}
